1 /****************************************************************************************
3 ** Copyright (C) 2013 Jolla Ltd.
4 ** Contact: Carsten Munk <carsten.munk@jollamobile.com>
5 ** All rights reserved.
7 ** This file is part of Wayland enablement for libhybris
9 ** You may use this file under the terms of the GNU Lesser General
10 ** Public License version 2.1 as published by the Free Software Foundation
11 ** and appearing in the file license.lgpl included in the packaging
14 ** This library is free software; you can redistribute it and/or
15 ** modify it under the terms of the GNU Lesser General Public
16 ** License version 2.1 as published by the Free Software Foundation
17 ** and appearing in the file license.lgpl included in the packaging
20 ** This library is distributed in the hope that it will be useful,
21 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 ** Lesser General Public License for more details.
25 ****************************************************************************************/
28 #include "wayland_window.h"
29 #include "wayland-egl-priv.h"
35 #include <android/android-version.h>
36 #include <eglhybris.h>
38 #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2
40 #include <android/sync/sync.h>
46 void WaylandNativeWindowBuffer::wlbuffer_from_native_handle(struct android_wlegl
*android_wlegl
)
50 struct android_wlegl_handle
*wlegl_handle
;
53 ints_data
= (int*) wl_array_add(&ints
, handle
->numInts
*sizeof(int));
54 memcpy(ints_data
, handle
->data
+ handle
->numFds
, handle
->numInts
*sizeof(int));
56 wlegl_handle
= android_wlegl_create_handle(android_wlegl
, handle
->numFds
, &ints
);
58 wl_array_release(&ints
);
60 for (int i
= 0; i
< handle
->numFds
; i
++) {
61 android_wlegl_handle_add_fd(wlegl_handle
, handle
->data
[i
]);
64 wlbuffer
= android_wlegl_create_buffer(android_wlegl
,
65 width
, height
, stride
,
66 format
, usage
, wlegl_handle
);
68 android_wlegl_handle_destroy(wlegl_handle
);
71 void WaylandNativeWindow::resize_callback(struct wl_egl_window
*egl_window
, void *)
73 TRACE("%dx%d",egl_window
->width
,egl_window
->height
);
74 native_window_set_buffers_dimensions(
75 (WaylandNativeWindow
*)egl_window
->nativewindow
,
76 egl_window
->width
,egl_window
->height
);
79 void WaylandNativeWindow::lock()
81 pthread_mutex_lock(&this->mutex
);
84 void WaylandNativeWindow::unlock()
86 pthread_mutex_unlock(&this->mutex
);
90 WaylandNativeWindow::registry_handle_global(void *data
, struct wl_registry
*registry
, uint32_t name
,
91 const char *interface
, uint32_t version
)
93 WaylandNativeWindow
*nw
= static_cast<WaylandNativeWindow
*>(data
);
95 if (strcmp(interface
, "android_wlegl") == 0) {
96 nw
->m_android_wlegl
= static_cast<struct android_wlegl
*>(wl_registry_bind(registry
, name
, &android_wlegl_interface
, 1));
100 static const struct wl_registry_listener registry_listener
= {
101 WaylandNativeWindow::registry_handle_global
106 WaylandNativeWindow::sync_callback(void *data
, struct wl_callback
*callback
, uint32_t serial
)
108 int *done
= static_cast<int *>(data
);
111 wl_callback_destroy(callback
);
114 static const struct wl_callback_listener sync_listener
= {
115 WaylandNativeWindow::sync_callback
119 WaylandNativeWindow::wayland_roundtrip(WaylandNativeWindow
*display
)
121 struct wl_callback
*callback
;
122 int done
= 0, ret
= 0;
123 wl_display_dispatch_queue_pending(display
->m_display
, display
->wl_queue
);
125 callback
= wl_display_sync(display
->m_display
);
126 wl_callback_add_listener(callback
, &sync_listener
, &done
);
127 wl_proxy_set_queue((struct wl_proxy
*) callback
, display
->wl_queue
);
128 while (ret
== 0 && !done
)
129 ret
= wl_display_dispatch_queue(display
->m_display
, display
->wl_queue
);
134 static void check_fatal_error(struct wl_display
*display
)
136 int error
= wl_display_get_error(display
);
141 fprintf(stderr
, "Wayland display got fatal error %i: %s\n", error
, strerror(error
));
144 fprintf(stderr
, "Additionally, errno was set to %i: %s\n", errno
, strerror(errno
));
146 fprintf(stderr
, "The display is now unusable, aborting.\n");
151 wayland_frame_callback(void *data
, struct wl_callback
*callback
, uint32_t time
)
153 WaylandNativeWindow
*surface
= static_cast<WaylandNativeWindow
*>(data
);
155 wl_callback_destroy(callback
);
158 static const struct wl_callback_listener frame_listener
= {
159 wayland_frame_callback
162 WaylandNativeWindow::WaylandNativeWindow(struct wl_egl_window
*window
, struct wl_display
*display
, const gralloc_module_t
* gralloc
, alloc_device_t
* alloc_device
)
166 HYBRIS_TRACE_BEGIN("wayland-platform", "create_window", "");
167 this->m_window
= window
;
168 this->m_window
->nativewindow
= (void *) this;
169 this->m_display
= display
;
170 this->m_width
= window
->width
;
171 this->m_height
= window
->height
;
172 this->m_defaultWidth
= window
->width
;
173 this->m_defaultHeight
= window
->height
;
174 this->m_window
->resize_callback
= resize_callback
;
176 this->wl_queue
= wl_display_create_queue(display
);
177 this->frame_callback
= NULL
;
178 this->registry
= wl_display_get_registry(display
);
179 wl_proxy_set_queue((struct wl_proxy
*) this->registry
,
181 wl_registry_add_listener(this->registry
, ®istry_listener
, this);
183 wayland_ok
= wayland_roundtrip(this);
184 assert(wayland_ok
>= 0);
185 assert(this->m_android_wlegl
!= NULL
);
187 this->m_gralloc
= gralloc
;
188 this->m_alloc
= alloc_device
;
190 m_usage
=GRALLOC_USAGE_HW_RENDER
| GRALLOC_USAGE_HW_TEXTURE
;
191 pthread_mutex_init(&mutex
, NULL
);
192 pthread_cond_init(&cond
, NULL
);
195 HYBRIS_TRACE_END("wayland-platform", "create_window", "");
198 WaylandNativeWindow::~WaylandNativeWindow()
200 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= m_bufList
.begin();
201 for (; it
!= m_bufList
.end(); it
++)
203 WaylandNativeWindowBuffer
* buf
=*it
;
205 wl_buffer_destroy(buf
->wlbuffer
);
206 buf
->wlbuffer
= NULL
;
207 buf
->common
.decRef(&buf
->common
);
210 wl_callback_destroy(frame_callback
);
211 wl_registry_destroy(registry
);
212 wl_event_queue_destroy(wl_queue
);
213 android_wlegl_destroy(m_android_wlegl
);
216 void WaylandNativeWindow::frame() {
217 HYBRIS_TRACE_BEGIN("wayland-platform", "frame_event", "");
219 this->frame_callback
= NULL
;
221 HYBRIS_TRACE_END("wayland-platform", "frame_event", "");
225 // overloads from BaseNativeWindow
226 int WaylandNativeWindow::setSwapInterval(int interval
) {
227 TRACE("interval:%i", interval
);
232 wl_buffer_release(void *data
, struct wl_buffer
*buffer
)
234 WaylandNativeWindow
*win
= static_cast<WaylandNativeWindow
*>(data
);
235 win
->releaseBuffer(buffer
);
238 static struct wl_buffer_listener wl_buffer_listener
= {
242 void WaylandNativeWindow::releaseBuffer(struct wl_buffer
*buffer
)
245 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= posted
.begin();
247 for (; it
!= posted
.end(); it
++)
249 if ((*it
)->wlbuffer
== buffer
)
253 if (it
!= posted
.end())
255 WaylandNativeWindowBuffer
* pwnb
= *it
;
257 TRACE("released posted buffer: %p", buffer
);
259 pthread_cond_signal(&cond
);
264 it
= fronted
.begin();
266 for (; it
!= fronted
.end(); it
++)
268 if ((*it
)->wlbuffer
== buffer
)
271 assert(it
!= fronted
.end());
275 WaylandNativeWindowBuffer
* wnb
= *it
;
277 HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted
.size());
279 for (it
= m_bufList
.begin(); it
!= m_bufList
.end(); it
++)
284 assert(it
!= m_bufList
.end());
285 HYBRIS_TRACE_BEGIN("wayland-platform", "releaseBuffer", "-%p", wnb
);
289 HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs
);
290 for (it
= m_bufList
.begin(); it
!= m_bufList
.end(); it
++)
297 pthread_cond_signal(&cond
);
298 HYBRIS_TRACE_END("wayland-platform", "releaseBuffer", "-%p", wnb
);
303 int WaylandNativeWindow::dequeueBuffer(BaseNativeWindowBuffer
**buffer
, int *fenceFd
){
304 HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer", "");
306 WaylandNativeWindowBuffer
*wnb
=NULL
;
310 HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_wait_for_buffer", "");
312 HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs
);
314 while (m_freeBufs
==0) {
315 HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs
);
317 pthread_cond_wait(&cond
,&mutex
);
319 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= m_bufList
.begin();
320 for (; it
!= m_bufList
.end(); it
++)
324 if ((*it
)->youngest
== 1)
329 if (it
==m_bufList
.end()) {
330 HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_worst_case_scenario", "");
331 HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_worst_case_scenario", "");
333 it
= m_bufList
.begin();
334 for (; it
!= m_bufList
.end() && (*it
)->busy
; it
++)
338 if (it
==m_bufList
.end()) {
340 HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_no_free_buffers", "");
341 HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_no_free_buffers", "");
342 TRACE("%p: no free buffers", buffer
);
348 HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_wait_for_buffer", "");
350 /* If the buffer doesn't match the window anymore, re-allocate */
351 if (wnb
->width
!= m_window
->width
|| wnb
->height
!= m_window
->height
352 || wnb
->format
!= m_format
|| wnb
->usage
!= m_usage
)
354 TRACE("wnb:%p,win:%p %i,%i %i,%i x%x,x%x x%x,x%x",
356 wnb
->width
,m_window
->width
, wnb
->height
,m_window
->height
,
357 wnb
->format
,m_format
, wnb
->usage
,m_usage
);
367 HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs
);
368 HYBRIS_TRACE_BEGIN("wayland-platform", "dequeueBuffer_gotBuffer", "-%p", wnb
);
369 HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_gotBuffer", "-%p", wnb
);
370 HYBRIS_TRACE_END("wayland-platform", "dequeueBuffer_wait_for_buffer", "");
376 int WaylandNativeWindow::lockBuffer(BaseNativeWindowBuffer
* buffer
){
377 WaylandNativeWindowBuffer
*wnb
= (WaylandNativeWindowBuffer
*) buffer
;
378 HYBRIS_TRACE_BEGIN("wayland-platform", "lockBuffer", "-%p", wnb
);
379 HYBRIS_TRACE_END("wayland-platform", "lockBuffer", "-%p", wnb
);
383 int WaylandNativeWindow::postBuffer(ANativeWindowBuffer
* buffer
)
386 WaylandNativeWindowBuffer
*wnb
= NULL
;
389 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= post_registered
.begin();
390 for (; it
!= post_registered
.end(); it
++)
392 if ((*it
)->other
== buffer
)
401 wnb
= new WaylandNativeWindowBuffer(buffer
);
403 wnb
->common
.incRef(&wnb
->common
);
404 buffer
->common
.incRef(&buffer
->common
);
412 /* XXX locking/something is a bit fishy here */
413 while (this->frame_callback
&& ret
!= -1) {
414 ret
= wl_display_dispatch_queue(m_display
, this->wl_queue
);
418 TRACE("wl_display_dispatch_queue returned an error:%i", ret
);
419 check_fatal_error(m_display
);
424 this->frame_callback
= wl_surface_frame(m_window
->surface
);
425 wl_callback_add_listener(this->frame_callback
, &frame_listener
, this);
426 wl_proxy_set_queue((struct wl_proxy
*) this->frame_callback
, this->wl_queue
);
428 if (wnb
->wlbuffer
== NULL
)
430 wnb
->wlbuffer_from_native_handle(m_android_wlegl
);
431 TRACE("%p add listener with %p inside", wnb
, wnb
->wlbuffer
);
432 wl_buffer_add_listener(wnb
->wlbuffer
, &wl_buffer_listener
, this);
433 wl_proxy_set_queue((struct wl_proxy
*) wnb
->wlbuffer
, this->wl_queue
);
434 post_registered
.push_back(wnb
);
436 TRACE("%p DAMAGE AREA: %dx%d", wnb
, wnb
->width
, wnb
->height
);
437 wl_surface_attach(m_window
->surface
, wnb
->wlbuffer
, 0, 0);
438 wl_surface_damage(m_window
->surface
, 0, 0, wnb
->width
, wnb
->height
);
439 wl_surface_commit(m_window
->surface
);
441 //pthread_cond_signal(&cond);
442 posted
.push_back(wnb
);
448 static int debugenvchecked
= 0;
450 int WaylandNativeWindow::queueBuffer(BaseNativeWindowBuffer
* buffer
, int fenceFd
)
452 WaylandNativeWindowBuffer
*wnb
= (WaylandNativeWindowBuffer
*) buffer
;
455 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer", "-%p", wnb
);
459 /* XXX locking/something is a bit fishy here */
460 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb
);
462 while (this->frame_callback
&& ret
!= -1) {
463 ret
= wl_display_dispatch_queue(m_display
, this->wl_queue
);
468 TRACE("wl_display_dispatch_queue returned an error");
469 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb
);
470 check_fatal_error(m_display
);
474 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb
);
479 if (debugenvchecked
== 0)
481 if (getenv("HYBRIS_WAYLAND_DUMP_BUFFERS") != NULL
)
486 if (debugenvchecked
== 2)
488 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb
);
489 hybris_dump_buffer_to_file(wnb
->getNativeBuffer());
490 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb
);
494 #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2
495 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb
);
496 sync_wait(fenceFd
, -1);
498 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb
);
501 this->frame_callback
= wl_surface_frame(m_window
->surface
);
502 wl_callback_add_listener(this->frame_callback
, &frame_listener
, this);
503 wl_proxy_set_queue((struct wl_proxy
*) this->frame_callback
, this->wl_queue
);
505 if (wnb
->wlbuffer
== NULL
)
507 wnb
->wlbuffer_from_native_handle(m_android_wlegl
);
508 TRACE("%p add listener with %p inside", wnb
, wnb
->wlbuffer
);
509 wl_buffer_add_listener(wnb
->wlbuffer
, &wl_buffer_listener
, this);
510 wl_proxy_set_queue((struct wl_proxy
*) wnb
->wlbuffer
, this->wl_queue
);
512 TRACE("%p DAMAGE AREA: %dx%d", wnb
, wnb
->width
, wnb
->height
);
513 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy
*) wnb
->wlbuffer
));
515 wl_surface_attach(m_window
->surface
, wnb
->wlbuffer
, 0, 0);
516 wl_surface_damage(m_window
->surface
, 0, 0, wnb
->width
, wnb
->height
);
517 wl_surface_commit(m_window
->surface
);
518 wl_display_flush(m_display
);
519 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy
*) wnb
->wlbuffer
));
522 //pthread_cond_signal(&cond);
523 fronted
.push_back(wnb
);
524 HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted
.size());
526 if (fronted
.size() == m_bufList
.size())
528 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb
);
530 /* We have fronted all our buffers, let's wait for one of them to be free */
533 ret
= wl_display_dispatch_queue(m_display
, this->wl_queue
);
537 check_fatal_error(m_display
);
540 HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted
.size());
542 if (fronted
.size() != m_bufList
.size())
545 HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb
);
547 HYBRIS_TRACE_END("wayland-platform", "queueBuffer", "-%p", wnb
);
553 int WaylandNativeWindow::cancelBuffer(BaseNativeWindowBuffer
* buffer
, int fenceFd
){
554 std::list
<WaylandNativeWindowBuffer
*>::iterator it
;
555 WaylandNativeWindowBuffer
*wnb
= (WaylandNativeWindowBuffer
*) buffer
;
558 HYBRIS_TRACE_BEGIN("wayland-platform", "cancelBuffer", "-%p", wnb
);
560 /* Check first that it really is our buffer */
561 for (it
= m_bufList
.begin(); it
!= m_bufList
.end(); it
++)
566 assert(it
!= m_bufList
.end());
570 HYBRIS_TRACE_COUNTER("wayland-platform", "m_freeBufs", "%i", m_freeBufs
);
572 for (it
= m_bufList
.begin(); it
!= m_bufList
.end(); it
++)
578 pthread_cond_signal(&cond
);
580 HYBRIS_TRACE_END("wayland-platform", "cancelBuffer", "-%p", wnb
);
585 unsigned int WaylandNativeWindow::width() const {
586 TRACE("value:%i", m_width
);
590 unsigned int WaylandNativeWindow::height() const {
591 TRACE("value:%i", m_height
);
595 unsigned int WaylandNativeWindow::format() const {
596 TRACE("value:%i", m_format
);
600 unsigned int WaylandNativeWindow::defaultWidth() const {
601 TRACE("value:%i", m_defaultWidth
);
602 return m_defaultWidth
;
605 unsigned int WaylandNativeWindow::defaultHeight() const {
606 TRACE("value:%i", m_defaultHeight
);
607 return m_defaultHeight
;
610 unsigned int WaylandNativeWindow::queueLength() const {
615 unsigned int WaylandNativeWindow::type() const {
617 #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=3
618 /* https://android.googlesource.com/platform/system/core/+/bcfa910611b42018db580b3459101c564f802552%5E!/ */
619 return NATIVE_WINDOW_SURFACE
;
621 return NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT
;
625 unsigned int WaylandNativeWindow::transformHint() const {
630 int WaylandNativeWindow::setBuffersFormat(int format
) {
631 if (format
!= m_format
)
633 TRACE("old-format:x%x new-format:x%x", m_format
, format
);
635 /* Buffers will be re-allocated when dequeued */
637 TRACE("format:x%x", format
);
642 void WaylandNativeWindow::destroyBuffer(WaylandNativeWindowBuffer
* wnb
)
644 TRACE("wnb:%p", wnb
);
648 wl_buffer_destroy(wnb
->wlbuffer
);
649 wnb
->wlbuffer
= NULL
;
650 wnb
->common
.decRef(&wnb
->common
);
654 void WaylandNativeWindow::destroyBuffers()
658 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= m_bufList
.begin();
659 for (; it
!=m_bufList
.end(); ++it
)
667 WaylandNativeWindowBuffer
*WaylandNativeWindow::addBuffer() {
669 WaylandNativeWindowBuffer
*wnb
= new WaylandNativeWindowBuffer(m_alloc
, m_width
, m_height
, m_format
, m_usage
);
670 m_bufList
.push_back(wnb
);
671 wnb
->common
.incRef(&wnb
->common
);
674 TRACE("wnb:%p width:%i height:%i format:x%x usage:x%x",
675 wnb
, wnb
->width
, wnb
->height
, wnb
->format
, wnb
->usage
);
681 int WaylandNativeWindow::setBufferCount(int cnt
) {
684 TRACE("cnt:%d", cnt
);
686 if (m_bufList
.size() == cnt
)
691 if (m_bufList
.size() > cnt
) {
692 /* Decreasing buffer count, remove from beginning */
693 std::list
<WaylandNativeWindowBuffer
*>::iterator it
= m_bufList
.begin();
694 for (int i
= 0; i
<= m_bufList
.size() - cnt
; i
++ )
698 m_bufList
.pop_front();
702 /* Increasing buffer count, start from current size */
703 for (int i
= m_bufList
.size(); i
< cnt
; i
++)
704 WaylandNativeWindowBuffer
*unused
= addBuffer();
716 int WaylandNativeWindow::setBuffersDimensions(int width
, int height
) {
717 if (m_width
!= width
|| m_height
!= height
)
719 TRACE("old-size:%ix%i new-size:%ix%i", m_width
, m_height
, width
, height
);
720 m_width
= m_defaultWidth
= width
;
721 m_height
= m_defaultHeight
= height
;
722 /* Buffers will be re-allocated when dequeued */
724 TRACE("size:%ix%i", width
, height
);
729 int WaylandNativeWindow::setUsage(int usage
) {
730 if ((usage
| GRALLOC_USAGE_HW_TEXTURE
) != m_usage
)
732 TRACE("old-usage:x%x new-usage:x%x", m_usage
, usage
);
733 m_usage
= usage
| GRALLOC_USAGE_HW_TEXTURE
;
734 /* Buffers will be re-allocated when dequeued */
736 TRACE("usage:x%x", usage
);
740 // vim: noai:ts=4:sw=4:ss=4:expandtab