From d78d8d4298f1b586db2c9f5a34ffc801cbc8173b Mon Sep 17 00:00:00 2001 From: "Mun, Gwan-gyeong" Date: Mon, 5 Sep 2016 22:42:27 +0900 Subject: [PATCH 01/16] tpl_wayland_vk_wsi: Change strerror to strerror_r for the guaranteee of thread safety. Change-Id: I5947b09c64c439ef9433b5f9c8f47e73d7fa55b9 Signed-off-by: Mun, Gwan-gyeong --- src/tpl_wayland_vk_wsi.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/tpl_wayland_vk_wsi.c b/src/tpl_wayland_vk_wsi.c index e9469ae..3e266e2 100644 --- a/src/tpl_wayland_vk_wsi.c +++ b/src/tpl_wayland_vk_wsi.c @@ -417,8 +417,11 @@ __tpl_wayland_vk_wsi_surface_enqueue_buffer(tpl_surface_t *surface, if (sync_fence != -1) { /* non worker thread mode */ /* TODO: set max wait time */ - if (tbm_sync_fence_wait(sync_fence, -1) != 1) - TPL_ERR("Failed to wait sync. | error: %d(%s)", errno, strerror(errno)); + if (tbm_sync_fence_wait(sync_fence, -1) != 1) { + char buf[1024]; + strerror_r(errno, buf, sizeof(buf)); + TPL_ERR("Failed to wait sync. | error: %d(%s)", errno, buf); + } close(sync_fence); } @@ -554,8 +557,11 @@ __tpl_wayland_vk_wsi_surface_dequeue_buffer(tpl_surface_t *surface, *sync_fence = tbm_sync_fence_create(wayland_vk_wsi_buffer->sync_timeline, name, wayland_vk_wsi_buffer->sync_timestamp); - if (*sync_fence == -1) - TPL_ERR("Failed to create TBM sync fence: %d(%s)", errno, strerror(errno)); + if (*sync_fence == -1) { + char buf[1024]; + strerror_r(errno, buf, sizeof(buf)); + TPL_ERR("Failed to create TBM sync fence: %d(%s)", errno, buf); + } } else { *sync_fence = -1; } @@ -585,7 +591,9 @@ __tpl_wayland_vk_wsi_surface_dequeue_buffer(tpl_surface_t *surface, *sync_fence = -1; wayland_vk_wsi_buffer->sync_timeline = tbm_sync_timeline_create(); if (wayland_vk_wsi_buffer->sync_timeline == -1) { - TPL_ERR("Failed to create TBM sync timeline: %d(%s)", errno, strerror(errno)); + char buf[1024]; + strerror_r(errno, buf, sizeof(buf)); + TPL_ERR("Failed to create TBM sync timeline: %d(%s)", errno, buf); wl_proxy_destroy(wl_proxy); tbm_surface_internal_unref(tbm_surface); free(wayland_vk_wsi_buffer); @@ -948,8 +956,11 @@ __tpl_wayland_vk_wsi_worker_thread_loop(void *arg) __tpl_wayland_vk_wsi_get_wayland_buffer_from_tbm_surface(tbm_surface); TPL_ASSERT(wayland_vk_wsi_buffer); if (wayland_vk_wsi_buffer->wait_sync != -1) { - if (tbm_sync_fence_wait(wayland_vk_wsi_buffer->wait_sync, -1) != 1) - TPL_ERR("Failed to wait sync. | error: %d(%s)", errno, strerror(errno)); + if (tbm_sync_fence_wait(wayland_vk_wsi_buffer->wait_sync, -1) != 1) { + char buf[1024]; + strerror_r(errno, buf, sizeof(buf)); + TPL_ERR("Failed to wait sync. | error: %d(%s)", errno, buf); + } close(wayland_vk_wsi_buffer->wait_sync); wayland_vk_wsi_buffer->wait_sync = -1; } -- 2.7.4 From d3c3f181659b46f8cb6d09278712940ea16aa32b Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Tue, 6 Sep 2016 18:17:22 +0900 Subject: [PATCH 02/16] tpl_wayland_egl: Add object locking mechanism for multi-threads client. - In the multi-threads environment, backend surface's locking mechanism(using tpl_object_t) is needed in order to prevent the case that the tpl_list is concurrently accessed by wayland_event of multi-threaded client. Change-Id: I2957a2893f469d2b8eb3fc4b4c30dd9da3cdfeff Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 67 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 2a994c1..3aa1181 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -40,6 +40,7 @@ struct _tpl_wayland_egl_display { }; struct _tpl_wayland_egl_surface { + tpl_object_t base; tbm_surface_queue_h tbm_queue; tbm_surface_h current_buffer; tpl_bool_t resized; @@ -374,12 +375,15 @@ __cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue, wayland_egl_surface->reset = TPL_TRUE; + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + /* Set the reset flag of the buffers which attached but not released to TPL_TRUE. */ __tpl_wayland_egl_buffer_set_reset_flag(wayland_egl_surface->attached_buffers); /* Set the reset flag of the buffers which dequeued but not enqueued to TPL_TRUE. */ __tpl_wayland_egl_buffer_set_reset_flag(wayland_egl_surface->dequeued_buffers); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); } static tpl_result_t @@ -437,6 +441,13 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) return TPL_ERROR_INVALID_OPERATION; } + if (__tpl_object_init(&wayland_egl_surface->base, TPL_OBJECT_SURFACE, + NULL) != TPL_ERROR_NONE) { + TPL_ERR("Failed to initialize backend surface's base class!"); + free(wayland_egl_surface); + return TPL_ERROR_INVALID_OPERATION; + } + surface->backend.data = (void *)wayland_egl_surface; wayland_egl_surface->tbm_queue = NULL; wayland_egl_surface->resized = TPL_FALSE; @@ -587,6 +598,7 @@ __tpl_wayland_egl_surface_fini(tpl_surface_t *surface) * the list of attached_buffers in order to free the created resources. * (tpl_wayland_egl_buffer_t or wl_buffer) */ if (wayland_egl_surface->attached_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); while (!__tpl_list_is_empty(wayland_egl_surface->attached_buffers)) { tbm_surface_h tbm_surface = __tpl_list_pop_front(wayland_egl_surface->attached_buffers, NULL); @@ -595,14 +607,18 @@ __tpl_wayland_egl_surface_fini(tpl_surface_t *surface) __tpl_list_free(wayland_egl_surface->attached_buffers, NULL); wayland_egl_surface->attached_buffers = NULL; + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); } /* the list of dequeued_buffers just does deletion */ if (wayland_egl_surface->dequeued_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); __tpl_list_free(wayland_egl_surface->dequeued_buffers, NULL); wayland_egl_surface->dequeued_buffers = NULL; + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); } + __tpl_object_fini(&wayland_egl_surface->base); free(wayland_egl_surface); surface->backend.data = NULL; } @@ -697,9 +713,13 @@ __tpl_wayland_egl_surface_commit(tpl_surface_t *surface, wl_egl_window->surface, wl_egl_window, wl_egl_window->width, wl_egl_window->height, wayland_egl_buffer->wl_proxy); - /* Start tracking of this tbm_surface until release_cb called. */ - __tpl_list_push_back(wayland_egl_surface->attached_buffers, - (void *)tbm_surface); + if (wayland_egl_surface->attached_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + /* Start tracking of this tbm_surface until release_cb called. */ + __tpl_list_push_back(wayland_egl_surface->attached_buffers, + (void *)tbm_surface); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } /* TPL_WAIT_VBLANK = 1 */ if (wayland_egl_display->tdm_client) { @@ -758,9 +778,13 @@ __tpl_wayland_egl_surface_enqueue_buffer(tpl_surface_t *surface, close(sync_fence); } - /* Stop tracking of this render_done tbm_surface. */ - __tpl_list_remove_data(wayland_egl_surface->dequeued_buffers, - (void *)tbm_surface, TPL_FIRST, NULL); + if (wayland_egl_surface->dequeued_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + /* Stop tracking of this render_done tbm_surface. */ + __tpl_list_remove_data(wayland_egl_surface->dequeued_buffers, + (void *)tbm_surface, TPL_FIRST, NULL); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } wayland_egl_buffer = __tpl_wayland_egl_get_wayland_buffer_from_tbm_surface(tbm_surface); @@ -1011,9 +1035,14 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, wayland_egl_buffer->wl_proxy, tbm_surface, tbm_bo_export(wayland_egl_buffer->bo)); - /* Start tracking of this tbm_surface until enqueue */ - __tpl_list_push_back(wayland_egl_surface->dequeued_buffers, - (void *)tbm_surface); + if (wayland_egl_surface->dequeued_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + /* Start tracking of this tbm_surface until enqueue */ + __tpl_list_push_back(wayland_egl_surface->dequeued_buffers, + (void *)tbm_surface); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } + return tbm_surface; } @@ -1071,8 +1100,13 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, wayland_egl_buffer, wayland_egl_buffer->wl_proxy, tbm_surface, tbm_bo_export(wayland_egl_buffer->bo)); - __tpl_list_push_back(wayland_egl_surface->dequeued_buffers, - (void *)tbm_surface); + if (wayland_egl_surface->dequeued_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + __tpl_list_push_back(wayland_egl_surface->dequeued_buffers, + (void *)tbm_surface); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } + return tbm_surface; } @@ -1199,10 +1233,13 @@ __cb_client_buffer_release_callback(void *data, struct wl_proxy *proxy) if (wayland_egl_buffer) { wayland_egl_surface = wayland_egl_buffer->wayland_egl_surface; - /* Stop tracking of this released tbm_surface. */ - __tpl_list_remove_data(wayland_egl_surface->attached_buffers, - (void *)tbm_surface, TPL_FIRST, NULL); - + if (wayland_egl_surface->attached_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + /* Stop tracking of this released tbm_surface. */ + __tpl_list_remove_data(wayland_egl_surface->attached_buffers, + (void *)tbm_surface, TPL_FIRST, NULL); + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } /* If tbm_surface_queue was reset before release_cb called out, * tbm_surface_queue_release doesn't have to be done. */ if (wayland_egl_buffer->reset == TPL_FALSE) -- 2.7.4 From 66532f5dc25e2ed997a3d1e927b0d645bdaac150 Mon Sep 17 00:00:00 2001 From: Sangjin Lee Date: Thu, 8 Sep 2016 14:28:12 +0900 Subject: [PATCH 03/16] tpl_wayland_egl: Use seperated event-queue for wl_tbm. the tdm_client related protocol provides wl_tbm, wl_tbm_queue and wl_buffer proxy. if wl_tbm proxy uses the seperated queue from wl_display, then wl_tbm_queue and wl_buffer also use the seperated queue by inherited from wl_tbm proxy's queue. ( if wl_tbm_queue and wl_buffer are gotten before setting of wl_tbm proxy queue. this machanism does not work. therefore, wl_tbm_queue and wl_buffer use wl_display's default queue.) - this patch chages the timing of handling of wl_buffer_release event. wl_buffer_release event is only handled before dequeue_buffer. reference: 1. wl_tbm proxy handles what received below wayland events. - buffer_attached_with_id - buffer_attached_with_fd 2. wl_tbm_queue handles what received below wayland events. - active - deactive Change-Id: Iac8b07016aae3418563ab5b5cc181fa8d2e7712f --- src/tpl_wayland_egl.c | 138 +++++++++++++------------------------------------- 1 file changed, 36 insertions(+), 102 deletions(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 2a994c1..751555c 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -37,6 +37,7 @@ struct _tpl_wayland_egl_display { struct wl_proxy *wl_tbm; /* wayland_tbm_client proxy */ tdm_client *tdm_client; struct wl_display *wl_dpy; + struct wl_event_queue *wl_tbm_event_queue; }; struct _tpl_wayland_egl_surface { @@ -48,7 +49,6 @@ struct _tpl_wayland_egl_surface { tpl_bool_t vblank_done; tpl_list_t *attached_buffers; /* list for tracking [ACQ]~[REL] buffers */ tpl_list_t *dequeued_buffers; /* list for tracking [DEQ]~[ENQ] buffers */ - struct wl_proxy *wl_tbm_queue; /* wl_tbm_queue proxy */ }; struct _tpl_wayland_egl_buffer { @@ -159,6 +159,16 @@ __tpl_wayland_egl_display_init(tpl_display_t *display) goto free_wl_display; } + wayland_egl_display->wl_tbm_event_queue = + wl_display_create_queue(wl_dpy); + if (!wayland_egl_display->wl_tbm_event_queue) { + TPL_ERR("Failed to create wl_event_queue."); + goto free_wl_display; + } + + wl_proxy_set_queue(wayland_egl_display->wl_tbm, + wayland_egl_display->wl_tbm_event_queue); + if (env == NULL || atoi(env)) { TPL_LOG_B("WL_EGL", "[INIT] ENABLE wait vblank."); wayland_egl_display->tdm_client = tdm_client_create(&tdm_err); @@ -185,11 +195,16 @@ __tpl_wayland_egl_display_init(tpl_display_t *display) free_wl_display: if (wayland_egl_display) { + if ((wayland_egl_display->wl_tbm) && (wayland_egl_display->wl_tbm_event_queue)) + wl_proxy_set_queue(wayland_egl_display->wl_tbm, NULL); if (wayland_egl_display->wl_tbm_client) wayland_tbm_client_deinit(wayland_egl_display->wl_tbm_client); if (wayland_egl_display->tdm_client) tdm_client_destroy(wayland_egl_display->tdm_client); + if (wayland_egl_display->wl_tbm_event_queue) + wl_event_queue_destroy(wayland_egl_display->wl_tbm_event_queue); + wayland_egl_display->wl_tbm_event_queue = NULL; wayland_egl_display->wl_tbm_client = NULL; wayland_egl_display->tdm_client = NULL; wayland_egl_display->wl_tbm = NULL; @@ -213,12 +228,19 @@ __tpl_wayland_egl_display_fini(tpl_display_t *display) TPL_LOG_B("WL_EGL", "[FINI] tpl_wayland_egl_display_t(%p) wl_tbm_client(%p)", wayland_egl_display, wayland_egl_display->wl_tbm_client); + if ((wayland_egl_display->wl_tbm) && (wayland_egl_display->wl_tbm_event_queue)) + wl_proxy_set_queue(wayland_egl_display->wl_tbm, NULL); + if (wayland_egl_display->wl_tbm_client) wayland_tbm_client_deinit(wayland_egl_display->wl_tbm_client); if (wayland_egl_display->tdm_client) tdm_client_destroy(wayland_egl_display->tdm_client); + if (wayland_egl_display->wl_tbm_event_queue) + wl_event_queue_destroy(wayland_egl_display->wl_tbm_event_queue); + + wayland_egl_display->wl_tbm_event_queue = NULL; wayland_egl_display->wl_tbm_client = NULL; wayland_egl_display->tdm_client = NULL; wayland_egl_display->wl_tbm = NULL; @@ -461,24 +483,6 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) wl_egl_window->width, wl_egl_window->height, TBM_FORMAT_ARGB8888); - - /* libtpl-egl processes the wl_proxy(wl_tbm_queue) event at dequeue. - * When libtpl-egl gets the activate event from wl_tbm_queue, - * it gets the scanout wl_buffer from the display server. - * When libtpl-egl gets the decativate event from wl_tbm_queue, - * it release the sacnout wl_buffer and allocates the offscreen wl_buffer - * at the client-side. - * The activate/decactivate events is sent from the display server - * at the no-comoposite mode and the composite mode. - */ - wayland_egl_surface->wl_tbm_queue = - (struct wl_proxy *)wayland_tbm_client_get_wl_tbm_queue( - wayland_egl_display->wl_tbm_client, - wl_egl_window->surface); - if (!wayland_egl_surface->wl_tbm_queue) { - TPL_ERR("Failed to get tbm_queue from wayland_tbm_client."); - return TPL_ERROR_INVALID_OPERATION; - } } else /*Why wl_surafce is NULL ?*/ wayland_egl_surface->tbm_queue = tbm_surface_queue_sequence_create( @@ -836,90 +840,35 @@ __tpl_wayland_egl_surface_validate(tpl_surface_t *surface) static tpl_result_t __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) { - struct wl_event_queue *queue = NULL; tpl_wayland_egl_display_t *wayland_egl_display = NULL; tpl_wayland_egl_surface_t *wayland_egl_surface = NULL; - tpl_wayland_egl_buffer_t *wayland_egl_buffer = NULL; - tbm_surface_h buffers[CLIENT_QUEUE_SIZE]; - int num = 0, i; tpl_result_t ret = TPL_ERROR_NONE; wayland_egl_display = (tpl_wayland_egl_display_t *) surface->display->backend.data; wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; - wl_display_dispatch_pending(wayland_egl_display->wl_dpy); if (tbm_surface_queue_can_dequeue(wayland_egl_surface->tbm_queue, 0)) return TPL_ERROR_NONE; - tbm_surface_queue_get_surfaces(wayland_egl_surface->tbm_queue, buffers, &num); - if (num == 0) { - TPL_ERR("tbm_queue(%p) has no buffer", wayland_egl_surface->tbm_queue); - return TPL_ERROR_INVALID_OPERATION; - } - - queue = wl_display_create_queue(wayland_egl_display->wl_dpy); - if (!queue) { - TPL_ERR("failed to create new wl_display queue."); - return TPL_ERROR_INVALID_OPERATION; - } - - for (i = 0; i < num; i++) { - wayland_egl_buffer = - __tpl_wayland_egl_get_wayland_buffer_from_tbm_surface(buffers[i]); - if (wayland_egl_buffer && wayland_egl_buffer->wl_proxy) - wl_proxy_set_queue(wayland_egl_buffer->wl_proxy, queue); - } + TRACE_BEGIN("WAITING FOR DEQUEUEABLE"); + TPL_OBJECT_UNLOCK(surface); - /* wayland_egl_display->wl_tbm has to receive below wayland events. - * - buffer_attached_with_id - * - buffer_attached_with_fd + /* Dispatching "wayland_egl_display->wl_tbm_event_queue" handles + * wl_buffer_release event, wl_tbm event, and wl_tbm_queue event. * - * wayland_egl_surface->wl_tbm_queue has to receive below wayland events. - * - active - * - deactive - * - * When wayland_egl_surface->wl_tbm_queue - * or wayland_egl_display->wl_tbm( == wayland_tbm_client) - * could not receive any events, tpl_surface cannot get a buffer. - * - * So, we have to manage event queue about [wl_tbm_queue, wayland_tbm_client] - * along with wl_buffer. + * 1. wl_tbm proxy handles what received below wayland events. + * - buffer_attached_with_id + * - buffer_attached_with_fd + * 2. wl_tbm_queue handles what received below wayland events. + * - active + * - deactive */ - - if (wayland_egl_surface->wl_tbm_queue) - wl_proxy_set_queue(wayland_egl_surface->wl_tbm_queue, queue); - - if (wayland_egl_display->wl_tbm) - wl_proxy_set_queue(wayland_egl_display->wl_tbm, queue); - - wl_display_dispatch_pending(wayland_egl_display->wl_dpy); - - if (tbm_surface_queue_can_dequeue(wayland_egl_surface->tbm_queue, 0)) { - for (i = 0; i < num; i++) { - wayland_egl_buffer = - __tpl_wayland_egl_get_wayland_buffer_from_tbm_surface(buffers[i]); - if (wayland_egl_buffer && wayland_egl_buffer->wl_proxy) - wl_proxy_set_queue(wayland_egl_buffer->wl_proxy, NULL); - } - - if (wayland_egl_surface->wl_tbm_queue) - wl_proxy_set_queue(wayland_egl_surface->wl_tbm_queue, NULL); - - if (wayland_egl_display->wl_tbm) - wl_proxy_set_queue(wayland_egl_display->wl_tbm, NULL); - - wl_event_queue_destroy(queue); - - return TPL_ERROR_NONE; - } - - TRACE_BEGIN("WAITING FOR DEQUEUEABLE"); - TPL_OBJECT_UNLOCK(surface); while (tbm_surface_queue_can_dequeue( wayland_egl_surface->tbm_queue, 0) == 0) { /* Application sent all buffers to the server. Wait for server response. */ - if (wl_display_dispatch_queue(wayland_egl_display->wl_dpy, queue) == -1) { + if (wl_display_dispatch_queue(wayland_egl_display->wl_dpy, + wayland_egl_display->wl_tbm_event_queue) == -1) { ret = TPL_ERROR_INVALID_OPERATION; TPL_ERR("falied to wl_display_dispatch_queue."); break; @@ -928,27 +877,12 @@ __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) TPL_OBJECT_LOCK(surface); TRACE_END(); - for (i = 0; i < num; i++) { - wayland_egl_buffer = - __tpl_wayland_egl_get_wayland_buffer_from_tbm_surface(buffers[i]); - if (wayland_egl_buffer && wayland_egl_buffer->wl_proxy) - wl_proxy_set_queue(wayland_egl_buffer->wl_proxy, NULL); - } - - if (wayland_egl_surface->wl_tbm_queue) - wl_proxy_set_queue(wayland_egl_surface->wl_tbm_queue, NULL); - - if (wayland_egl_display->wl_tbm) - wl_proxy_set_queue(wayland_egl_display->wl_tbm, NULL); - - wl_event_queue_destroy(queue); return ret; } static tbm_surface_h __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, - uint64_t timeout_ns, - tbm_fd *sync_fence) + uint64_t timeout_ns, tbm_fd *sync_fence) { TPL_ASSERT(surface); TPL_ASSERT(surface->backend.data); -- 2.7.4 From 019e7ff6cade7d660524cb23f7b7c442011a07dd Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Mon, 19 Sep 2016 19:59:01 +0900 Subject: [PATCH 04/16] tpl_wayland_egl: dispatching before checking whether can dequeue or not. - The event processing can be delayed in case there are idle buffer in free queue. So, in dequeueable procedure, it has to call wl_display_dispatch_queue_pending before checking whether tbm_surface_queue can dequeue or not. It can process that the events related to 'queue flush' more rapidly. Change-Id: I5512e576e985d57dc9181e338f589d344f2b8161 Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index fe892ba..af23333 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -872,6 +872,9 @@ __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) surface->display->backend.data; wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; + wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, + wayland_egl_display->wl_tbm_event_queue); + if (tbm_surface_queue_can_dequeue(wayland_egl_surface->tbm_queue, 0)) return TPL_ERROR_NONE; -- 2.7.4 From 73106ab4db76751bd212a1186ef3afac76f5ad24 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Thu, 22 Sep 2016 11:41:44 +0900 Subject: [PATCH 05/16] tpl: Fixed image dump util. Change-Id: I8c1727194fb1934cda60f6d413590ecc2ff0eb73 Signed-off-by: joonbum.ko --- Makefile | 6 +- packaging/libtpl-egl.spec | 10 +- src/tpl_gbm.c | 6 +- src/tpl_utils.h | 236 +++------------------------------------------- src/tpl_wayland_egl.c | 7 +- src/tpl_wayland_vk_wsi.c | 7 +- 6 files changed, 23 insertions(+), 249 deletions(-) diff --git a/Makefile b/Makefile index e18a35a..23e82a8 100644 --- a/Makefile +++ b/Makefile @@ -47,10 +47,8 @@ endif ifneq ($(call is-feature-enabled,default_log),) CFLAGS += -DLOG_DEFAULT_ENABLE endif -ifneq ($(call is-feature-enabled,pngdump),) - CFLAGS += -DPNG_DUMP_ENABLE - CFLAGS += `pkg-config --cflags libpng` - LDFLAGS += `pkg-config --libs libpng` +ifneq ($(call is-feature-enabled,default_dump),) + CFLAGS += -DDEFAULT_DUMP_ENABLE endif ifneq ($(call is-feature-enabled,object_hash_check),) CFLAGS += -DOBJECT_HASH_CHECK diff --git a/packaging/libtpl-egl.spec b/packaging/libtpl-egl.spec index 64438e8..2eb175c 100644 --- a/packaging/libtpl-egl.spec +++ b/packaging/libtpl-egl.spec @@ -12,7 +12,7 @@ %define ENABLE_TTRACE 0 %define ENABLE_DLOG 0 %define ENABLE_DEFAULT_LOG 0 -%define ENABLE_PNG_DUMP 0 +%define ENABLE_DEFAULT_DUMP 0 %define ENABLE_OBJECT_HASH_CHECK 1 #WAYLAND-EGL VERSION MACROS %define WL_EGL_VERSION 1.0.0 @@ -73,10 +73,6 @@ BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(wayland-tbm-server) %endif -%if "%{ENABLE_PNG_DUMP}" == "1" -BuildRequires: pkgconfig(libpng) -%endif - %if "%{ENABLE_TTRACE}" == "1" BuildRequires: pkgconfig(ttrace) %endif @@ -147,8 +143,8 @@ TPL_OPTIONS=${TPL_OPTIONS}-dlog TPL_OPTIONS=${TPL_OPTIONS}-default_log %endif -%if "%{ENABLE_PNG_DUMP}" == "1" -TPL_OPTIONS=${TPL_OPTIONS}-pngdump +%if "%{ENABLE_DEFAULT_DUMP}" == "1" +TPL_OPTIONS=${TPL_OPTIONS}-default_dump %endif %if "%{ENABLE_OBJECT_HASH_CHECK}" == "1" diff --git a/src/tpl_gbm.c b/src/tpl_gbm.c index d0d4bcf..d5d43ce 100644 --- a/src/tpl_gbm.c +++ b/src/tpl_gbm.c @@ -339,7 +339,6 @@ __tpl_gbm_surface_enqueue_buffer(tpl_surface_t *surface, { tpl_gbm_buffer_t *gbm_buffer = NULL; tpl_gbm_surface_t *gbm_surface = NULL; - tbm_bo_handle bo_handle; TPL_ASSERT(surface); TPL_ASSERT(surface->display); @@ -369,10 +368,7 @@ __tpl_gbm_surface_enqueue_buffer(tpl_surface_t *surface, TRACE_ASYNC_END((int)gbm_buffer, "[DEQ]~[ENQ] BO_NAME:%d", tbm_bo_export(gbm_buffer->bo)); - bo_handle = tbm_bo_get_handle(gbm_buffer->bo, TBM_DEVICE_CPU); - if (bo_handle.ptr) - TPL_IMAGE_DUMP(bo_handle.ptr, surface->width, surface->height, - surface->dump_count++); + TPL_IMAGE_DUMP(tbm_surface, surface->width, surface->height); tbm_surface_internal_unref(tbm_surface); diff --git a/src/tpl_utils.h b/src/tpl_utils.h index d8b832a..7c1696e 100644 --- a/src/tpl_utils.h +++ b/src/tpl_utils.h @@ -47,9 +47,8 @@ #include #include -#ifdef PNG_DUMP_ENABLE -#include -#endif /* PNG_DUMP_ENABLE */ +#include +#include /* 0:uninitialized, 1:initialized,no log, 2:user log */ extern unsigned int tpl_log_lvl; @@ -233,11 +232,14 @@ extern unsigned int tpl_dump_lvl; } \ } -#define TPL_IMAGE_DUMP(data, width, height, num) \ +#ifdef DEFAULT_DUMP_ENABLE +#define TPL_IMAGE_DUMP __tpl_util_image_dump +#else +#define TPL_IMAGE_DUMP(data, width, height) \ { \ if (tpl_dump_lvl != 0) \ { \ - __tpl_util_image_dump(__func__, data, tpl_dump_lvl, width, height, num); \ + __tpl_util_image_dump(data, width, height); \ } \ else \ { \ @@ -248,10 +250,10 @@ extern unsigned int tpl_dump_lvl; tpl_dump_lvl = atoi(env); \ \ if (tpl_dump_lvl != 0) \ - __tpl_util_image_dump(__func__, data, tpl_dump_lvl, width, height, num);\ + __tpl_util_image_dump(data, width, height); \ } \ } - +#endif typedef struct _tpl_list_node tpl_list_node_t; @@ -646,223 +648,13 @@ tpl_list_pop_back(tpl_list_t *list, tpl_free_func_t func) return data; } -static TPL_INLINE int -__tpl_util_image_dump_bmp(const char *file, const void *data, int width, - int height) -{ - int i; - - struct { - unsigned char magic[2]; - } bmpfile_magic = { {'B', 'M'} }; - - struct { - unsigned int filesz; - unsigned short creator1; - unsigned short creator2; - unsigned int bmp_offset; - } bmpfile_header = { 0, 0, 0, 0x36 }; - - struct { - unsigned int header_sz; - unsigned int width; - unsigned int height; - unsigned short nplanes; - unsigned short bitspp; - unsigned int compress_type; - unsigned int bmp_bytesz; - unsigned int hres; - unsigned int vres; - unsigned int ncolors; - unsigned int nimpcolors; - } bmp_dib_v3_header_t = { 0x28, 0, 0, 1, 24, 0, 0, 0, 0, 0, 0 }; - unsigned int *blocks; - - if (data == NULL) return -1; - - if (width <= 0 || height <= 0) return -1; - - FILE *fp = NULL; - if ((fp = fopen (file, "wb")) == NULL) { - char ment[256]; - strerror_r(errno, ment, 256); - printf("FILE ERROR:%s\t", ment); - return -2; - } else { - bmpfile_header.filesz = sizeof (bmpfile_magic) + sizeof (bmpfile_header) + - sizeof (bmp_dib_v3_header_t) + width * height * 3; - bmp_dib_v3_header_t.header_sz = sizeof (bmp_dib_v3_header_t); - bmp_dib_v3_header_t.width = width; - bmp_dib_v3_header_t.height = -height; - bmp_dib_v3_header_t.nplanes = 1; - bmp_dib_v3_header_t.bmp_bytesz = width * height * 3; - - if (fwrite(&bmpfile_magic, sizeof (bmpfile_magic), 1, fp) < 1) { - fclose (fp); - return -1; - } - if (fwrite(&bmpfile_header, sizeof (bmpfile_header), 1, fp) < 1) { - fclose (fp); - return -1; - } - if (fwrite(&bmp_dib_v3_header_t, sizeof (bmp_dib_v3_header_t), 1, fp) < 1) { - fclose (fp); - return -1; - } - - blocks = (unsigned int *)data; - for (i = 0; i < height * width; i++) { - if (fwrite(&blocks[i], 3, 1, fp) < 1) { - fclose(fp); - return -1; - } - } - - fclose (fp); - } - - return 0; -} - -#ifdef PNG_DUMP_ENABLE -#define PNG_DEPTH 8 -static TPL_INLINE int -__tpl_util_image_dump_png(const char *file, const void *data, int width, - int height) -{ - TPL_CHECK_ON_FALSE_RETURN_VAL(data != NULL, -1); - TPL_CHECK_ON_FALSE_RETURN_VAL(width > 0, -1); - TPL_CHECK_ON_FALSE_RETURN_VAL(height > 0, -1); - - FILE *fp = fopen(file, "wb"); - int res = -2; - - if (fp) { - res = -1; - png_structp pPngStruct = - png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (pPngStruct) { - png_infop pPngInfo = png_create_info_struct(pPngStruct); - - if (pPngInfo) { - png_init_io(pPngStruct, fp); - png_set_IHDR(pPngStruct, - pPngInfo, - width, - height, - PNG_DEPTH, - PNG_COLOR_TYPE_RGBA, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - png_set_bgr(pPngStruct); - png_write_info(pPngStruct, pPngInfo); - - const int pixel_size = 4; // RGBA - png_bytep *row_pointers = - png_malloc(pPngStruct, height * sizeof(png_byte *)); - if (!row_pointers) { - fclose(fp); - return res; - } - - unsigned int *blocks = (unsigned int *) data; - int y = 0; - int x = 0; - - for (; y < height; ++y) { - png_bytep row = png_malloc(pPngStruct, - sizeof(png_byte) * width * - pixel_size); - if (!row) { - fclose(fp); - return res; - } - - row_pointers[y] = (png_bytep) row; - - for (x = 0; x < width; ++x) { - unsigned int curBlock = blocks[y * width + x]; - - row[x * pixel_size] = (curBlock & 0xFF); - row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF; - row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF; - row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF; - } - } - - png_write_image(pPngStruct, row_pointers); - png_write_end(pPngStruct, pPngInfo); - - for (y = 0; y < height; y++) { - png_free(pPngStruct, row_pointers[y]); - } - png_free(pPngStruct, row_pointers); - - png_destroy_write_struct(&pPngStruct, &pPngInfo); - - res = 0; - } - } - fclose(fp); - } - - return res; -} -#endif - static TPL_INLINE void -__tpl_util_image_dump(const char *func, const void *data, int type, - int width, int height, int num) +__tpl_util_image_dump(void *data, int width, int height) { - char name[200]; - char path_name[20] = "/tmp/tpl_dump"; + char path_name[20] = "/tmp"; - if (mkdir (path_name, 0755) == -1) { - if (errno != EEXIST) { - TPL_ERR("Directory creation error!"); - return; - } - } - - if (type == 1) { - snprintf(name, sizeof(name), "%s/[%d][%s][%d][%d][%04d].bmp", - path_name, getpid(), func, width, height, num); - - /*snprintf(name, sizeof(name), "[%d][%04d]", getpid(), num);*/ - switch (__tpl_util_image_dump_bmp(name, data, width, height)) { - case 0: - TPL_DEBUG("%s file is dumped\n", name); - break; - case -1: - TPL_ERR("Dump failed..internal error (data = %p)(width = %d)(height = %d)\n", - data, width, height); - break; - case -2: - TPL_ERR("Dump failed..file pointer error\n"); - break; - } - } -#ifdef PNG_DUMP_ENABLE - else { - snprintf(name, sizeof(name), "%s/[%d][%s][%d][%d][%04d].png", - path_name, getpid(), func, width, height, num); - - /*snprintf(name, sizeof(name), "[%d][%04d]", getpid(), num);*/ - switch (__tpl_util_image_dump_png(name, data, width, height)) { - case 0: - TPL_DEBUG("%s file is dumped\n", name); - break; - case -1: - TPL_ERR("Dump failed..internal error (data = %p)(width = %d)(height = %d)\n", - data, width, height); - break; - case -2: - TPL_ERR("Dump failed..file pointer error\n"); - break; - } - } -#endif + tbm_surface_internal_dump_start(path_name, width, height, 1); + tbm_surface_internal_dump_buffer((tbm_surface_h)data, "png"); + tbm_surface_internal_dump_end(); } #endif /* TPL_UTILS_H */ diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index af23333..d04e209 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -678,12 +678,9 @@ __tpl_wayland_egl_surface_commit(tpl_surface_t *surface, TRACE_ASYNC_END((int)wayland_egl_buffer, "[DEQ]~[ENQ] BO_NAME:%d", tbm_bo_export(wayland_egl_buffer->bo)); - tbm_bo_handle bo_handle = - tbm_bo_get_handle(wayland_egl_buffer->bo , TBM_DEVICE_CPU); - if (bo_handle.ptr) - TPL_IMAGE_DUMP(bo_handle.ptr, surface->width, surface->height, - surface->dump_count++); + TPL_IMAGE_DUMP(tbm_surface, surface->width, surface->height); + wl_surface_attach(wl_egl_window->surface, (void *)wayland_egl_buffer->wl_proxy, wl_egl_window->dx, wl_egl_window->dy); diff --git a/src/tpl_wayland_vk_wsi.c b/src/tpl_wayland_vk_wsi.c index 3e266e2..69e1fbf 100644 --- a/src/tpl_wayland_vk_wsi.c +++ b/src/tpl_wayland_vk_wsi.c @@ -390,12 +390,7 @@ __tpl_wayland_vk_wsi_surface_enqueue_buffer(tpl_surface_t *surface, __tpl_wayland_vk_wsi_get_wayland_buffer_from_tbm_surface(tbm_surface); TPL_ASSERT(wayland_vk_wsi_buffer); - tbm_bo_handle bo_handle = - tbm_bo_get_handle(tbm_surface_internal_get_bo(tbm_surface, 0), TBM_DEVICE_CPU); - - if (bo_handle.ptr) - TPL_IMAGE_DUMP(bo_handle.ptr, surface->width, surface->height, - surface->dump_count++); + TPL_IMAGE_DUMP(tbm_surface, surface->width, surface->height); tbm_surface_internal_unref(tbm_surface); -- 2.7.4 From daf6ad30df340d1eec2b241c42c6183b914f7d71 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Thu, 22 Sep 2016 11:52:23 +0900 Subject: [PATCH 06/16] tpl_wayland_egl: Reused buffer's reset flag set to TPL_FALSE. Change-Id: I2edc82f5e61ccb35deb22bdefe9b888568a313f9 Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index d04e209..5c38105 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -969,6 +969,8 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, wayland_egl_buffer->wl_proxy, tbm_surface, tbm_bo_export(wayland_egl_buffer->bo)); + wayland_egl_buffer->reset = TPL_FALSE; + if (wayland_egl_surface->dequeued_buffers) { TPL_OBJECT_LOCK(&wayland_egl_surface->base); /* Start tracking of this tbm_surface until enqueue */ -- 2.7.4 From 5c4d65253daf0e6f8e1127f15cc0f5e0bedea979 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Thu, 22 Sep 2016 13:05:09 +0900 Subject: [PATCH 07/16] tpl_wayland_egl: Revert commit 'dispatching before checking whether can dequeue or not.' Change-Id: Ic053d5ce9d98ba94d09224541534f11e54575761 Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 5c38105..ff417de 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -869,9 +869,6 @@ __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) surface->display->backend.data; wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; - wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, - wayland_egl_display->wl_tbm_event_queue); - if (tbm_surface_queue_can_dequeue(wayland_egl_surface->tbm_queue, 0)) return TPL_ERROR_NONE; -- 2.7.4 From e3f5ff3d9fd36550ff8cf5640c4821754158251f Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Fri, 23 Sep 2016 13:47:45 +0900 Subject: [PATCH 08/16] tpl_wayland_egl: Release locks while tpl-egl waits for vblank done. - If error occurs on tdm_client_handle_events(), the worker thread may be faced the loop of unlimited. - As a result, after the next tpl_surface API is called , the main thread will be faced the dead lock state Change-Id: I7902678dad6120d540563279f35ccd5a344851cc Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index ff417de..afda052 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -636,14 +636,17 @@ __tpl_wayland_egl_surface_wait_vblank(tpl_surface_t *surface) tpl_wayland_egl_surface_t *wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; + TPL_OBJECT_UNLOCK(surface); do { tdm_err = tdm_client_handle_events(wayland_egl_display->tdm_client); if (tdm_err != TDM_ERROR_NONE) { TPL_ERR("Failed to tdm_client_handle_events."); + break; } } while (wayland_egl_surface->vblank_done == TPL_FALSE); + TPL_OBJECT_LOCK(surface); } static void -- 2.7.4 From 4815b6fe8c02fa2685817c8503eafe1dac26606a Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Fri, 23 Sep 2016 14:04:54 +0900 Subject: [PATCH 09/16] tpl_wayland_egl: Call wl_display_dispatch_queue_pending with wl_tbm_event_queue instead of dispatching with default_queue on __tpl_wayland_egl_surface_fini(). - __tpl_wayland_egl_surface_fini() should call wl_display_dispatch_queue_pending with wl_tbm_event_queue because of the wl_event_queue is seperated default_queue and wl_tbm_event_queue. Change-Id: I7b80e8752e4d056c4ee6fba5467503cd6c73c0db Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index afda052..8b969f2 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -582,7 +582,8 @@ __tpl_wayland_egl_surface_fini(tpl_surface_t *surface) } wl_display_flush(wayland_egl_display->wl_dpy); - wl_display_dispatch_pending(wayland_egl_display->wl_dpy); + wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, + wayland_egl_display->wl_tbm_event_queue); if (wayland_egl_surface->tdm_vblank) { TPL_LOG_B("WL_EGL", -- 2.7.4 From 257c88f515a54cc190f32accd2c78c580a192ed6 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Mon, 26 Sep 2016 10:49:06 +0900 Subject: [PATCH 10/16] tpl_wayland_egl: Fixed some bugs related to wl_display_dispatch_queue_pending. Temporal fix : Change of tbm_surface's reset state. - Currently, tbm_surface's reset state is changed by tpl_surface_validate() and tbm_surface_queue event handler. When we have good solution of changing of tbm_surface's reset state, tpl_surface_validate()'s wayland egl backend should remove changing of tbm_surface's reset state. - Fixed some bugs about ACTIVE/DEACTIVE(queue_flush) events and finally applied wl_display_dispatch_queue_pending(). - Related with below commit. 019e7ff6cade7d660524cb23f7b7c442011a07dd tpl_wayland_egl: dispatching before checking whether can dequeue or not. - The event processing can be delayed in case there are idle buffer in free queue. So, in dequeueable procedure, it has to call wl_display_dispatch_queue_pending before checking whether tbm_surface_queue can dequeue or not. It can process that the events related to 'queue flush' more rapidly. - In future commit, tpl_surface_validate will be modified to suitable one which is related to reset flag. Change-Id: I0584211aed14ef2dd22531074c3b50e8463dd95f Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 8b969f2..37c71fd 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -849,17 +849,30 @@ __tpl_wayland_egl_surface_enqueue_buffer(tpl_surface_t *surface, static tpl_bool_t __tpl_wayland_egl_surface_validate(tpl_surface_t *surface) { + tpl_bool_t retval = TPL_TRUE; + TPL_ASSERT(surface); TPL_ASSERT(surface->backend.data); tpl_wayland_egl_surface_t *wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; - if (wayland_egl_surface->resized || - wayland_egl_surface->reset) - return TPL_FALSE; + retval = !(wayland_egl_surface->reset || wayland_egl_surface->resized); + + /* TODO */ + /* Be planning to revise below line in future commits. + - It is under development so that EGL can realize tbm_surface_queue_reset + immediately. + */ + + /* The tbm_surface_queue_flush (which is occured by ACTIVE, DEACTIVE events) + * only occured in __tpl_wayland_egl_surface_wait_dequeable. + * After tpl_surface_dequeue_buffer(), tpl_surface has to inform to frontend + * surface was reset. (retval) + * The reset flag will be set to TPL_FALSE only here after inform it. */ + wayland_egl_surface->reset = TPL_FALSE; - return TPL_TRUE; + return retval; } static tpl_result_t @@ -873,6 +886,9 @@ __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) surface->display->backend.data; wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; + wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, + wayland_egl_display->wl_tbm_event_queue); + if (tbm_surface_queue_can_dequeue(wayland_egl_surface->tbm_queue, 0)) return TPL_ERROR_NONE; @@ -937,12 +953,12 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, format = tbm_surface_queue_get_format(wayland_egl_surface->tbm_queue); tbm_surface_queue_reset(wayland_egl_surface->tbm_queue, width, height, format); - wayland_egl_surface->resized = TPL_FALSE; surface->width = width; surface->height = height; - } - wayland_egl_surface->reset = TPL_FALSE; + wayland_egl_surface->resized = TPL_FALSE; + wayland_egl_surface->reset = TPL_FALSE; + } if (__tpl_wayland_egl_surface_wait_dequeuable(surface)) { TPL_ERR("Failed to wait dequeeable buffer"); @@ -1013,18 +1029,8 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, /* reset flag is to check whether it is the buffer before tbm_surface_queue is reset or not. */ wayland_egl_buffer->reset = TPL_FALSE; - wayland_egl_surface->current_buffer = tbm_surface; - /* - * Only when the tbm_surface which it dequeued after tbm_surface_queue_dequeue - * was called is not reused one, the following flag 'reset' has to - * initialize to TPL_FALSE. - * - * If this flag initialized before tbm_surface_queue_dequeue, it cause - * the problem that return TPL_FALSE in tpl_surface_validate() in spite of - * EGL already has valid buffer. - */ - wayland_egl_surface->reset = TPL_FALSE; + wayland_egl_surface->current_buffer = tbm_surface; __tpl_wayland_egl_set_wayland_buffer_to_tbm_surface(tbm_surface, wayland_egl_buffer); -- 2.7.4 From 295d42d2ef720b03fc47b86bba76ec1a17df90ce Mon Sep 17 00:00:00 2001 From: Sangjin Lee Date: Fri, 23 Sep 2016 16:04:07 +0900 Subject: [PATCH 11/16] tpl_wayland_egl: Use the tizen_surface_shm protocol for flushing of buffer If the client's state changes the deiconified state, the tizen display server sends tizen_surface_shm_flusher event to client. So, when the client gets the tizen_surface_shm_flusher event from server, client can flush buffers of surface_queue. And the tizen_surface_shm_flush event is dispatched by client's default event queue in tpl_wayland_egl. Change-Id: Icccb55e621fe264bf299d9d8c81e6f5376cee24d --- Makefile | 1 + src/protocol/tizen-surface-client.h | 103 ++++++++++++++++++++ src/protocol/tizen-surface-protocol.c | 36 +++++++ src/tpl_wayland_egl.c | 178 +++++++++++++++++++++++++++++++++- 4 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 src/protocol/tizen-surface-client.h create mode 100644 src/protocol/tizen-surface-protocol.c diff --git a/Makefile b/Makefile index 23e82a8..ee75eba 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,7 @@ ifneq ($(call is-feature-enabled,winsys_wl),) TPL_SRCS += $(SRC_DIR)/tpl_wayland_egl.c TPL_SRCS += $(SRC_DIR)/tpl_wayland_vk_wsi.c TPL_SRCS += $(SRC_DIR)/tpl_gbm.c +TPL_SRCS += $(SRC_DIR)/protocol/tizen-surface-protocol.c endif ifneq ($(call is-feature-enabled,winsys_dri2),) diff --git a/src/protocol/tizen-surface-client.h b/src/protocol/tizen-surface-client.h new file mode 100644 index 0000000..6159a82 --- /dev/null +++ b/src/protocol/tizen-surface-client.h @@ -0,0 +1,103 @@ +#ifndef TIZEN_SURFACE_CLIENT_PROTOCOL_H +#define TIZEN_SURFACE_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct tizen_surface_shm; +struct tizen_surface_shm_flusher; + +extern const struct wl_interface tizen_surface_shm_interface; +extern const struct wl_interface tizen_surface_shm_flusher_interface; + +#define TIZEN_SURFACE_SHM_GET_FLUSHER 0 + +static inline void +tizen_surface_shm_set_user_data(struct tizen_surface_shm *tizen_surface_shm, + void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) tizen_surface_shm, user_data); +} + +static inline void * +tizen_surface_shm_get_user_data(struct tizen_surface_shm *tizen_surface_shm) +{ + return wl_proxy_get_user_data((struct wl_proxy *) tizen_surface_shm); +} + +static inline void +tizen_surface_shm_destroy(struct tizen_surface_shm *tizen_surface_shm) +{ + wl_proxy_destroy((struct wl_proxy *) tizen_surface_shm); +} + +static inline struct tizen_surface_shm_flusher * +tizen_surface_shm_get_flusher(struct tizen_surface_shm *tizen_surface_shm, + struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) tizen_surface_shm, + TIZEN_SURFACE_SHM_GET_FLUSHER, &tizen_surface_shm_flusher_interface, NULL, + surface); + + return (struct tizen_surface_shm_flusher *) id; +} + +struct tizen_surface_shm_flusher_listener { + /** + * flush - (none) + */ + void (*flush)(void *data, + struct tizen_surface_shm_flusher *tizen_surface_shm_flusher); +}; + +static inline int +tizen_surface_shm_flusher_add_listener(struct tizen_surface_shm_flusher + *tizen_surface_shm_flusher, + const struct tizen_surface_shm_flusher_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) tizen_surface_shm_flusher, + (void (* *)(void)) listener, data); +} + +#define TIZEN_SURFACE_SHM_FLUSHER_DESTROY 0 + +static inline void +tizen_surface_shm_flusher_set_user_data(struct tizen_surface_shm_flusher + *tizen_surface_shm_flusher, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) tizen_surface_shm_flusher, + user_data); +} + +static inline void * +tizen_surface_shm_flusher_get_user_data(struct tizen_surface_shm_flusher + *tizen_surface_shm_flusher) +{ + return wl_proxy_get_user_data((struct wl_proxy *) tizen_surface_shm_flusher); +} + +static inline void +tizen_surface_shm_flusher_destroy(struct tizen_surface_shm_flusher + *tizen_surface_shm_flusher) +{ + wl_proxy_marshal((struct wl_proxy *) tizen_surface_shm_flusher, + TIZEN_SURFACE_SHM_FLUSHER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) tizen_surface_shm_flusher); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/protocol/tizen-surface-protocol.c b/src/protocol/tizen-surface-protocol.c new file mode 100644 index 0000000..8420280 --- /dev/null +++ b/src/protocol/tizen-surface-protocol.c @@ -0,0 +1,36 @@ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface tizen_surface_shm_flusher_interface; +extern const struct wl_interface wl_surface_interface; + +static const struct wl_interface *types[] = { + &tizen_surface_shm_flusher_interface, + &wl_surface_interface, +}; + +static const struct wl_message tizen_surface_shm_requests[] = { + { "get_flusher", "no", types + 0 }, +}; + +WL_EXPORT const struct wl_interface tizen_surface_shm_interface = { + "tizen_surface_shm", 1, + 1, tizen_surface_shm_requests, + 0, NULL, +}; + +static const struct wl_message tizen_surface_shm_flusher_requests[] = { + { "destroy", "", types + 0 }, +}; + +static const struct wl_message tizen_surface_shm_flusher_events[] = { + { "flush", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface tizen_surface_shm_flusher_interface = { + "tizen_surface_shm_flusher", 1, + 1, tizen_surface_shm_flusher_requests, + 1, tizen_surface_shm_flusher_events, +}; + diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 37c71fd..4ff75bd 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -23,6 +23,7 @@ #include #include #include +#include "protocol/tizen-surface-client.h" /* In wayland, application and compositor create its own drawing buffers. Recommend size is more than 2. */ #define CLIENT_QUEUE_SIZE 3 @@ -38,6 +39,7 @@ struct _tpl_wayland_egl_display { tdm_client *tdm_client; struct wl_display *wl_dpy; struct wl_event_queue *wl_tbm_event_queue; + struct tizen_surface_shm *tizen_surface_shm; /* used for surface buffer_flush */ }; struct _tpl_wayland_egl_surface { @@ -50,6 +52,7 @@ struct _tpl_wayland_egl_surface { tpl_bool_t vblank_done; tpl_list_t *attached_buffers; /* list for tracking [ACQ]~[REL] buffers */ tpl_list_t *dequeued_buffers; /* list for tracking [DEQ]~[ENQ] buffers */ + struct tizen_surface_shm_flusher *tizen_surface_shm_flusher; /* wl_proxy for buffer flush */ }; struct _tpl_wayland_egl_buffer { @@ -67,8 +70,16 @@ static const struct wl_buffer_listener buffer_release_listener; static int tpl_wayland_egl_buffer_key; #define KEY_tpl_wayland_egl_buffer (unsigned long)(&tpl_wayland_egl_buffer_key) -static void __tpl_wayland_egl_buffer_free(tpl_wayland_egl_buffer_t - *wayland_egl_buffer); +static void +__tpl_wayland_egl_display_buffer_flusher_init(tpl_display_t *display); +static void +__tpl_wayland_egl_display_buffer_flusher_fini(tpl_display_t *display); +static void +__tpl_wayland_egl_surface_buffer_flusher_init(tpl_surface_t *surface); +static void +__tpl_wayland_egl_surface_buffer_flusher_fini(tpl_surface_t *surface); +static void +__tpl_wayland_egl_buffer_free(tpl_wayland_egl_buffer_t *wayland_egl_buffer); static TPL_INLINE tpl_wayland_egl_buffer_t * __tpl_wayland_egl_get_wayland_buffer_from_tbm_surface(tbm_surface_h surface) @@ -183,6 +194,7 @@ __tpl_wayland_egl_display_init(tpl_display_t *display) } wayland_egl_display->wl_dpy = wl_dpy; + __tpl_wayland_egl_display_buffer_flusher_init(display); } else { TPL_ERR("Invalid native handle for display."); @@ -241,6 +253,8 @@ __tpl_wayland_egl_display_fini(tpl_display_t *display) if (wayland_egl_display->wl_tbm_event_queue) wl_event_queue_destroy(wayland_egl_display->wl_tbm_event_queue); + __tpl_wayland_egl_display_buffer_flusher_fini(display); + wayland_egl_display->wl_tbm_event_queue = NULL; wayland_egl_display->wl_tbm_client = NULL; wayland_egl_display->tdm_client = NULL; @@ -535,6 +549,8 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) } } + __tpl_wayland_egl_surface_buffer_flusher_init(surface); + TPL_LOG_B("WL_EGL", "[INIT] tpl_surface_t(%p) tpl_wayland_egl_surface_t(%p) tbm_queue(%p)", surface, wayland_egl_surface, @@ -597,6 +613,8 @@ __tpl_wayland_egl_surface_fini(tpl_surface_t *surface) wayland_egl_surface, wl_egl_window, wayland_egl_surface->tbm_queue); tbm_surface_queue_destroy(wayland_egl_surface->tbm_queue); wayland_egl_surface->tbm_queue = NULL; + + __tpl_wayland_egl_surface_buffer_flusher_fini(surface); } /* When surface is destroyed, unreference tbm_surface which tracked by @@ -923,7 +941,8 @@ __tpl_wayland_egl_surface_wait_dequeuable(tpl_surface_t *surface) static tbm_surface_h __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, - uint64_t timeout_ns, tbm_fd *sync_fence) + uint64_t timeout_ns, + tbm_fd *sync_fence) { TPL_ASSERT(surface); TPL_ASSERT(surface->backend.data); @@ -1223,3 +1242,156 @@ __cb_client_window_resize_callback(struct wl_egl_window *wl_egl_window, || (height != tbm_surface_queue_get_height(wayland_egl_surface->tbm_queue))) wayland_egl_surface->resized = TPL_TRUE; } + +void +__cb_resistry_global_callback(void *data, struct wl_registry *wl_registry, + uint32_t name, const char *interface, + uint32_t version) +{ + tpl_wayland_egl_display_t *wayland_egl_display = data; + + if (!strcmp(interface, "tizen_surface_shm")) { + wayland_egl_display->tizen_surface_shm = + wl_registry_bind(wl_registry, + name, + &tizen_surface_shm_interface, + version); + } +} + +void +__cb_resistry_global_remove_callback(void *data, struct wl_registry *wl_registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + __cb_resistry_global_callback, + __cb_resistry_global_remove_callback +}; + +static void +__tpl_wayland_egl_display_buffer_flusher_init(tpl_display_t *display) +{ + tpl_wayland_egl_display_t *wayland_egl_display = display->backend.data; + struct wl_registry *registry = NULL; + struct wl_event_queue *queue = NULL; + int ret; + + queue = wl_display_create_queue(wayland_egl_display->wl_dpy); + if (!queue) { + TPL_ERR("Failed to create wl_queue"); + goto fini; + } + + registry = wl_display_get_registry(wayland_egl_display->wl_dpy); + if (!queue) { + TPL_ERR("Failed to create wl_registry"); + goto fini; + } + + wl_proxy_set_queue((struct wl_proxy *)registry, queue); + if (wl_registry_add_listener(registry, ®istry_listener, + wayland_egl_display)) { + TPL_ERR("Failed to wl_registry_add_listener"); + goto fini; + } + + ret = wl_display_roundtrip_queue(wayland_egl_display->wl_dpy, queue); + if (ret) { + TPL_ERR("Failed to wl_display_roundtrip_queue ret:%d, err:%d", ret, errno); + goto fini; + } + + /* set tizen_surface_shm's queue as client's default queue */ + if (wayland_egl_display->tizen_surface_shm) + wl_proxy_set_queue((struct wl_proxy *)wayland_egl_display->tizen_surface_shm, + NULL); + +fini: + if (queue) + wl_event_queue_destroy(queue); + if (registry) + wl_registry_destroy(registry); +} + +static void +__tpl_wayland_egl_display_buffer_flusher_fini(tpl_display_t *display) +{ + tpl_wayland_egl_display_t *wayland_egl_display = display->backend.data; + + if (wayland_egl_display->tizen_surface_shm) { + tizen_surface_shm_destroy(wayland_egl_display->tizen_surface_shm); + wayland_egl_display->tizen_surface_shm = NULL; + } +} + +static void __cb_tizen_surface_shm_flusher_flush_callback(void *data, + struct tizen_surface_shm_flusher *tizen_surface_shm_flusher) +{ + tpl_surface_t *surface = data; + tpl_wayland_egl_surface_t *wayland_egl_surface; + tpl_wayland_egl_display_t *wayland_egl_display; + int ret; + + TPL_CHECK_ON_NULL_RETURN(surface); + wayland_egl_surface = surface->backend.data; + TPL_CHECK_ON_NULL_RETURN(wayland_egl_surface); + TPL_CHECK_ON_NULL_RETURN(surface->display); + wayland_egl_display = surface->display->backend.data; + TPL_CHECK_ON_NULL_RETURN(wayland_egl_display); + + TPL_CHECK_ON_NULL_RETURN(wayland_egl_display->wl_dpy); + TPL_CHECK_ON_NULL_RETURN(wayland_egl_display->wl_tbm_event_queue); + TPL_CHECK_ON_NULL_RETURN(wayland_egl_surface->tbm_queue); + + /*Fist distach panding queue for TPL + - dispatch buffer-release + - dispatch queue flush + */ + ret = wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, + wayland_egl_display->wl_tbm_event_queue); + if (ret) { + TPL_ERR("Failed to wl_display_dispatch_queue_pending ret:%d, err:%d", ret, + errno); + return; + } + + tbm_surface_queue_flush(wayland_egl_surface->tbm_queue); +} + +static const struct tizen_surface_shm_flusher_listener + tizen_surface_shm_flusher_listener = { + __cb_tizen_surface_shm_flusher_flush_callback +}; + +static void +__tpl_wayland_egl_surface_buffer_flusher_init(tpl_surface_t *surface) +{ + tpl_wayland_egl_display_t *wayland_egl_display = surface->display->backend.data; + tpl_wayland_egl_surface_t *wayland_egl_surface = surface->backend.data; + struct wl_egl_window *wl_egl_window = (struct wl_egl_window *) + surface->native_handle; + + if (!wayland_egl_display->tizen_surface_shm) + return; + + wayland_egl_surface->tizen_surface_shm_flusher = + tizen_surface_shm_get_flusher(wayland_egl_display->tizen_surface_shm, + wl_egl_window->surface); + tizen_surface_shm_flusher_add_listener( + wayland_egl_surface->tizen_surface_shm_flusher, + &tizen_surface_shm_flusher_listener, surface); +} + +static void +__tpl_wayland_egl_surface_buffer_flusher_fini(tpl_surface_t *surface) +{ + tpl_wayland_egl_surface_t *wayland_egl_surface = surface->backend.data; + + if (wayland_egl_surface->tizen_surface_shm_flusher) { + tizen_surface_shm_flusher_destroy( + wayland_egl_surface->tizen_surface_shm_flusher); + wayland_egl_surface->tizen_surface_shm_flusher = NULL; + } +} -- 2.7.4 From 851992fc72282446ebf374c642af4361b3652f5a Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Wed, 5 Oct 2016 17:44:52 +0900 Subject: [PATCH 12/16] tpl_wayland_egl: Fix misused return value of wl_display_roundtrip_queue() on buffer_flusher_init() - If there are errors on wl_display_roundtrip_queue then it returns values as '-1'. Change-Id: I754df1768b46f0d815af84255255997429eefa7b Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 4ff75bd..7119bf2 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -1298,7 +1298,7 @@ __tpl_wayland_egl_display_buffer_flusher_init(tpl_display_t *display) } ret = wl_display_roundtrip_queue(wayland_egl_display->wl_dpy, queue); - if (ret) { + if (ret == -1) { TPL_ERR("Failed to wl_display_roundtrip_queue ret:%d, err:%d", ret, errno); goto fini; } -- 2.7.4 From 6e4b86832ee5726001be04da57da8ce614c87fb4 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Tue, 27 Sep 2016 18:41:29 +0900 Subject: [PATCH 13/16] tpl: Added frontend API "tpl_surface_set_reset_cb" - This API can set function of reset_cb to tpl_surface. - When the tbm_surface_queue_reset is occured, if there is reset_cb which is registered by frontend, tpl_surface calls that function of reset_cb with reset_data. - tpl_surface_validate() also can notify info of surface's "reset/resized states" to frontend as before. But if you want to know the surface reset state without render call, it is better that registers callback of reset, using above API. Change-Id: Ib762856ad1db306c435013218c1a4be2b24ef1c9 Signed-off-by: joonbum.ko --- src/tpl.h | 28 ++++++++++++++++++++++++++++ src/tpl_internal.h | 4 ++++ src/tpl_surface.c | 17 +++++++++++++++++ src/tpl_wayland_egl.c | 39 +++++++++++++++++++-------------------- 4 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/tpl.h b/src/tpl.h index cb48da9..76a3ad4 100644 --- a/src/tpl.h +++ b/src/tpl.h @@ -124,6 +124,11 @@ typedef struct _tpl_surface tpl_surface_t; typedef void (*tpl_free_func_t)(void *data); /** + * Function type used for registering callback function. + */ +typedef void (*tpl_surface_cb_func_t)(void *data); + +/** * Object types. * * @see tpl_object_get_type() @@ -695,6 +700,29 @@ tbm_surface_h tpl_display_get_buffer_from_native_pixmap(tpl_display_t *display, tpl_handle_t pixmap); +/** + * Set frontbuffer mode to render to only frontbuffer. + * + * @param surface surface to set mode. + * @param set TPL_TRUE if user want to set tpl_surface to frontbuffer mode. + * @return TPL_ERROR_NONE if tpl_surface is valid. + */ tpl_result_t tpl_surface_set_frontbuffer_mode(tpl_surface_t *surface, tpl_bool_t set); + +/** + * Set callback function to tpl_surface for receiving reset information. + * + * This function should be called when after tpl_surface_create() if + * frontend surface want to know that if surface reset or not. + * + * @param surface surface to set callback. It has to be not NULL. + * @param data data to be delivered to callback function. + * @param reset_cb pointer value of callback funtion. + * - It can be NULL if frontend wants to delete callback function. + * @return TPL_ERROR_NONE if tpl_surface is valid. + */ +tpl_result_t +tpl_surface_set_reset_cb(tpl_surface_t *surface, + void* data, tpl_surface_cb_func_t reset_cb); #endif /* TPL_H */ diff --git a/src/tpl_internal.h b/src/tpl_internal.h index 6231c87..41da0a4 100644 --- a/src/tpl_internal.h +++ b/src/tpl_internal.h @@ -132,6 +132,10 @@ struct _tpl_surface { /*For frontbuffer extension*/ tpl_bool_t is_frontbuffer_mode; tbm_surface_h frontbuffer; + + /* Surface reset callback */ + tpl_surface_cb_func_t reset_cb; + void* reset_data; }; /******************************************************************************* diff --git a/src/tpl_surface.c b/src/tpl_surface.c index d6ad51d..762a597 100644 --- a/src/tpl_surface.c +++ b/src/tpl_surface.c @@ -405,3 +405,20 @@ tpl_surface_set_frontbuffer_mode(tpl_surface_t *surface, tpl_bool_t set) surface, set ? "ACTIVATED" : "DEACTIVATED"); return ret; } + +tpl_result_t +tpl_surface_set_reset_cb(tpl_surface_t *surface, void *data, tpl_surface_cb_func_t reset_cb) +{ + tpl_result_t ret = TPL_ERROR_NONE; + + if (!surface) + { + TPL_ERR("Invalid surface!"); + return TPL_ERROR_INVALID_PARAMETER; + } + + surface->reset_data = data; + surface->reset_cb = reset_cb; + + return ret; +} diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 7119bf2..35c8556 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -47,7 +47,7 @@ struct _tpl_wayland_egl_surface { tbm_surface_queue_h tbm_queue; tbm_surface_h current_buffer; tpl_bool_t resized; - tpl_bool_t reset; /* TRUE if queue reseted by external */ + tpl_bool_t reset; /* TRUE if queue reseted by external */ tdm_client_vblank *tdm_vblank; /* vblank object for each wl_surface */ tpl_bool_t vblank_done; tpl_list_t *attached_buffers; /* list for tracking [ACQ]~[REL] buffers */ @@ -400,8 +400,14 @@ static void __cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue, void *data) { - tpl_wayland_egl_surface_t *wayland_egl_surface = - (tpl_wayland_egl_surface_t *)data; + tpl_surface_t *surface = NULL; + tpl_wayland_egl_surface_t *wayland_egl_surface = NULL; + + surface = (tpl_surface_t *)data; + TPL_CHECK_ON_NULL_RETURN(surface); + + wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; + TPL_CHECK_ON_NULL_RETURN(wayland_egl_surface); if (!wayland_egl_surface) return; @@ -409,10 +415,10 @@ __cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue, "[QUEUE_RESET_CB] tpl_wayland_egl_surface_t(%p) surface_queue(%p)", data, surface_queue); - wayland_egl_surface->reset = TPL_TRUE; - TPL_OBJECT_LOCK(&wayland_egl_surface->base); + wayland_egl_surface->reset = TPL_TRUE; + /* Set the reset flag of the buffers which attached but not released to TPL_TRUE. */ __tpl_wayland_egl_buffer_set_reset_flag(wayland_egl_surface->attached_buffers); @@ -420,6 +426,9 @@ __cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue, __tpl_wayland_egl_buffer_set_reset_flag(wayland_egl_surface->dequeued_buffers); TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + + if (surface->reset_cb) + surface->reset_cb(surface->reset_data); } static tpl_result_t @@ -487,6 +496,7 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) surface->backend.data = (void *)wayland_egl_surface; wayland_egl_surface->tbm_queue = NULL; wayland_egl_surface->resized = TPL_FALSE; + wayland_egl_surface->reset = TPL_FALSE; wayland_egl_surface->vblank_done = TPL_TRUE; wayland_egl_surface->current_buffer = NULL; @@ -526,7 +536,7 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) /* Set reset_callback to tbm_queue */ tbm_surface_queue_add_reset_cb(wayland_egl_surface->tbm_queue, __cb_tbm_surface_queue_reset_callback, - (void *)wayland_egl_surface); + (void *)surface); surface->width = wl_egl_window->width; @@ -875,20 +885,7 @@ __tpl_wayland_egl_surface_validate(tpl_surface_t *surface) tpl_wayland_egl_surface_t *wayland_egl_surface = (tpl_wayland_egl_surface_t *)surface->backend.data; - retval = !(wayland_egl_surface->reset || wayland_egl_surface->resized); - - /* TODO */ - /* Be planning to revise below line in future commits. - - It is under development so that EGL can realize tbm_surface_queue_reset - immediately. - */ - - /* The tbm_surface_queue_flush (which is occured by ACTIVE, DEACTIVE events) - * only occured in __tpl_wayland_egl_surface_wait_dequeable. - * After tpl_surface_dequeue_buffer(), tpl_surface has to inform to frontend - * surface was reset. (retval) - * The reset flag will be set to TPL_FALSE only here after inform it. */ - wayland_egl_surface->reset = TPL_FALSE; + retval = !(wayland_egl_surface->resized || wayland_egl_surface->reset); return retval; } @@ -1006,6 +1003,7 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, tbm_surface, tbm_bo_export(wayland_egl_buffer->bo)); wayland_egl_buffer->reset = TPL_FALSE; + wayland_egl_surface->reset = TPL_FALSE; if (wayland_egl_surface->dequeued_buffers) { TPL_OBJECT_LOCK(&wayland_egl_surface->base); @@ -1050,6 +1048,7 @@ __tpl_wayland_egl_surface_dequeue_buffer(tpl_surface_t *surface, wayland_egl_buffer->reset = TPL_FALSE; wayland_egl_surface->current_buffer = tbm_surface; + wayland_egl_surface->reset = TPL_FALSE; __tpl_wayland_egl_set_wayland_buffer_to_tbm_surface(tbm_surface, wayland_egl_buffer); -- 2.7.4 From 05708df85f03caa8dc8bee57d7e44d656bf2ea5d Mon Sep 17 00:00:00 2001 From: Sangjin Lee Date: Thu, 6 Oct 2016 10:56:33 +0900 Subject: [PATCH 14/16] tpl_wayland_egl: Fix error check for dispatch queue Change-Id: I8b2f684a160358b632e1edf2d1f28a8843b409ed --- src/tpl_wayland_egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 35c8556..bc5507f 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -1350,7 +1350,7 @@ static void __cb_tizen_surface_shm_flusher_flush_callback(void *data, */ ret = wl_display_dispatch_queue_pending(wayland_egl_display->wl_dpy, wayland_egl_display->wl_tbm_event_queue); - if (ret) { + if (ret == -1) { TPL_ERR("Failed to wl_display_dispatch_queue_pending ret:%d, err:%d", ret, errno); return; -- 2.7.4 From 805176455d44a88fc5bad0d6bf0066e1111b426f Mon Sep 17 00:00:00 2001 From: "Mun, Gwan-gyeong" Date: Thu, 6 Oct 2016 18:14:18 +0900 Subject: [PATCH 15/16] tpl: Add TPL_ERROR_OUT_OF_MEMORY to enum vaulue of tpl_result_t. - it provides error case of OOM (out of memory) for users of libtpl-egl. previous: tpl returns TPL_ERROR_INVALID_OPERATION or NULL when the tpl fails on allocation of memory. current : tpl returns TPL_ERROR_OUT_OF_MEMORY or NULL when the tpl fails on allocation of memory. Change-Id: I9859b71be94422b2f36250d62a7e68029f355072 Signed-off-by: Mun, Gwan-gyeong --- src/tpl.c | 2 +- src/tpl.h | 3 ++- src/tpl_gbm.c | 4 ++-- src/tpl_tbm.c | 12 ++++++------ src/tpl_utils.h | 2 +- src/tpl_utils_hlist.c | 2 +- src/tpl_wayland_egl.c | 4 ++-- src/tpl_wayland_vk_wsi.c | 13 ++++++++----- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/tpl.c b/src/tpl.c index 4f2ab38..ed4c8a1 100644 --- a/src/tpl.c +++ b/src/tpl.c @@ -18,7 +18,7 @@ __tpl_runtime_init() runtime = (tpl_runtime_t *) calloc(1, sizeof(tpl_runtime_t)); if (runtime == NULL) { TPL_ERR("Failed to allocate new tpl_runtime_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } } diff --git a/src/tpl.h b/src/tpl.h index 76a3ad4..b4a9fbe 100644 --- a/src/tpl.h +++ b/src/tpl.h @@ -204,7 +204,8 @@ typedef enum { typedef enum { TPL_ERROR_NONE = 0, /* Successfull */ TPL_ERROR_INVALID_PARAMETER, /* Invalid parmeter */ - TPL_ERROR_INVALID_OPERATION /* Invalid operation */ + TPL_ERROR_INVALID_OPERATION, /* Invalid operation */ + TPL_ERROR_OUT_OF_MEMORY /* Out of memory */ } tpl_result_t; /** diff --git a/src/tpl_gbm.c b/src/tpl_gbm.c index d5d43ce..6875db0 100644 --- a/src/tpl_gbm.c +++ b/src/tpl_gbm.c @@ -102,7 +102,7 @@ __tpl_gbm_display_init(tpl_display_t *display) } gbm_display = (tpl_gbm_display_t *) calloc(1, sizeof(tpl_gbm_display_t)); - if (!gbm_display) return TPL_ERROR_INVALID_PARAMETER; + if (!gbm_display) return TPL_ERROR_OUT_OF_MEMORY; display->bufmgr_fd = dup(gbm_device_get_fd(display->native_handle)); gbm_display->bufmgr = tbm_bufmgr_init(display->bufmgr_fd); @@ -263,7 +263,7 @@ __tpl_gbm_surface_init(tpl_surface_t *surface) tpl_gbm_surface = (tpl_gbm_surface_t *) calloc(1, sizeof(tpl_gbm_surface_t)); if (!tpl_gbm_surface) { TPL_ERR("Failed to allocate new gbm backend surface."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } surface->backend.data = (void *)tpl_gbm_surface; diff --git a/src/tpl_tbm.c b/src/tpl_tbm.c index a375008..b656306 100644 --- a/src/tpl_tbm.c +++ b/src/tpl_tbm.c @@ -30,16 +30,16 @@ __tpl_tbm_display_init(tpl_display_t *display) tbm_display = (tpl_tbm_display_t *) calloc(1, sizeof(tpl_tbm_display_t)); + if (!tbm_display) { + TPL_ERR("Failed to allocate memory for new tpl_tbm_display_t."); + return TPL_ERROR_OUT_OF_MEMORY; + } + if (!display->native_handle) { display->native_handle = tbm_bufmgr_init(-1); tbm_display->need_dpy_deinit = 1; } - if (!tbm_display) { - TPL_ERR("Failed to allocate memory for new tpl_tbm_display_t."); - return TPL_ERROR_INVALID_OPERATION; - } - display->backend.data = tbm_display; display->bufmgr_fd = -1; @@ -174,7 +174,7 @@ __tpl_tbm_surface_init(tpl_surface_t *surface) tpl_tbm_surface = (tpl_tbm_surface_t *) calloc(1, sizeof(tpl_tbm_surface_t)); if (!tpl_tbm_surface) { TPL_ERR("Failed to allocate memory for new tpl_tbm_surface_t"); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } surface->backend.data = (void *)tpl_tbm_surface; diff --git a/src/tpl_utils.h b/src/tpl_utils.h index 7c1696e..2b8580b 100644 --- a/src/tpl_utils.h +++ b/src/tpl_utils.h @@ -518,7 +518,7 @@ __tpl_list_insert(tpl_list_node_t *pos, void *data) tpl_list_node_t *node = (tpl_list_node_t *)malloc(sizeof(tpl_list_node_t)); if (!node) { TPL_ERR("Failed to allocate new tpl_list_node_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } node->data = data; diff --git a/src/tpl_utils_hlist.c b/src/tpl_utils_hlist.c index 4997732..283dced 100644 --- a/src/tpl_utils_hlist.c +++ b/src/tpl_utils_hlist.c @@ -211,7 +211,7 @@ __tpl_hashlist_insert(tpl_hlist_t *list, size_t key, void *data) new_node = (tpl_hlist_node_t *) malloc(sizeof(tpl_hlist_node_t)); if (!new_node) { TPL_ERR("Failed to allocate new tpl_hlist_node_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } hash = CALC_HASH(key); diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index bc5507f..99b957f 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -144,7 +144,7 @@ __tpl_wayland_egl_display_init(tpl_display_t *display) sizeof(tpl_wayland_egl_display_t)); if (!wayland_egl_display) { TPL_ERR("Failed to allocate memory for new tpl_wayland_egl_display_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } display->backend.data = wayland_egl_display; @@ -483,7 +483,7 @@ __tpl_wayland_egl_surface_init(tpl_surface_t *surface) sizeof(tpl_wayland_egl_surface_t)); if (!wayland_egl_surface) { TPL_ERR("Failed to allocate memory for new tpl_wayland_egl_surface_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } if (__tpl_object_init(&wayland_egl_surface->base, TPL_OBJECT_SURFACE, diff --git a/src/tpl_wayland_vk_wsi.c b/src/tpl_wayland_vk_wsi.c index 69e1fbf..febd7bd 100644 --- a/src/tpl_wayland_vk_wsi.c +++ b/src/tpl_wayland_vk_wsi.c @@ -167,7 +167,7 @@ __tpl_wayland_vk_wsi_display_init(tpl_display_t *display) sizeof(tpl_wayland_vk_wsi_display_t)); if (!wayland_vk_wsi_display) { TPL_ERR("Failed to allocate memory for new tpl_wayland_vk_wsi_display_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } wayland_vk_wsi_display->surface_capabilities.min_buffer = 2; @@ -288,7 +288,7 @@ __tpl_wayland_vk_wsi_surface_init(tpl_surface_t *surface) sizeof(tpl_wayland_vk_wsi_surface_t)); if (!wayland_vk_wsi_surface) { TPL_ERR("Failed to allocate memory for new tpl_wayland_vk_wsi_surface_t."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } surface->backend.data = (void *)wayland_vk_wsi_surface; @@ -624,6 +624,7 @@ __tpl_wayland_vk_wsi_surface_get_swapchain_buffers(tpl_surface_t *surface, tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL; tbm_surface_queue_error_e tsq_err; int i, dequeue_count; + tpl_result_t ret = TPL_ERROR_NONE; TPL_ASSERT(surface); TPL_ASSERT(surface->backend.data); @@ -636,7 +637,7 @@ __tpl_wayland_vk_wsi_surface_get_swapchain_buffers(tpl_surface_t *surface, wayland_vk_wsi_surface->buffer_count, sizeof(tbm_surface_h)); if (!swapchain_buffers) { TPL_ERR("Failed to allocate memory for buffers."); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } for (i = 0 ; i < wayland_vk_wsi_surface->buffer_count ; i++) { @@ -645,6 +646,7 @@ __tpl_wayland_vk_wsi_surface_get_swapchain_buffers(tpl_surface_t *surface, TPL_ERR("Failed to get tbm_surface from tbm_surface_queue | tsq_err = %d", tsq_err); dequeue_count = i; + ret = TPL_ERROR_OUT_OF_MEMORY; goto get_buffer_fail; } swapchain_buffers[i] = buffer; @@ -655,6 +657,7 @@ __tpl_wayland_vk_wsi_surface_get_swapchain_buffers(tpl_surface_t *surface, swapchain_buffers[i]); if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) { TPL_ERR("Failed to release tbm_surface. | tsq_err = %d", tsq_err); + ret = TPL_ERROR_INVALID_OPERATION; goto release_buffer_fail; } } @@ -675,7 +678,7 @@ get_buffer_fail: release_buffer_fail: free(swapchain_buffers); - return TPL_ERROR_INVALID_OPERATION; + return ret; } #if USE_WORKER_THREAD == 1 @@ -716,7 +719,7 @@ __tpl_wayland_vk_wsi_surface_create_swapchain(tpl_surface_t *surface, if (!wayland_vk_wsi_surface->tbm_queue) { TPL_ERR("TBM surface queue creation failed!"); - return TPL_ERROR_INVALID_OPERATION; + return TPL_ERROR_OUT_OF_MEMORY; } wayland_vk_wsi_surface->buffer_count = buffer_count; -- 2.7.4 From 29f03f4bf4ff4220a0c58270fe08ef14f5503ca7 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Thu, 6 Oct 2016 14:45:16 +0900 Subject: [PATCH 16/16] tpl_wayland_egl: Do unreference the attached buffers when the flushing of buffer is occured. it uses the list of attached_buffers. Change-Id: Iaf880e86807af33e75ad7ee41e682628db4216e1 Signed-off-by: joonbum.ko --- src/tpl_wayland_egl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tpl_wayland_egl.c b/src/tpl_wayland_egl.c index 99b957f..0323dfc 100644 --- a/src/tpl_wayland_egl.c +++ b/src/tpl_wayland_egl.c @@ -1357,6 +1357,23 @@ static void __cb_tizen_surface_shm_flusher_flush_callback(void *data, } tbm_surface_queue_flush(wayland_egl_surface->tbm_queue); + + /* Only when client call tpl_surface_dequeue_buffer(), client can do + * unreference tbm_surface although there are release events in the event queue, + * After tbm_surface_queue_flush, queue has no tbm_surface, client can do + * unreference attached buffers using the list of attached_buffers. + * Then, client does not need to wait for release_callback to unreference + * attached buffer. + */ + if (wayland_egl_surface->attached_buffers) { + TPL_OBJECT_LOCK(&wayland_egl_surface->base); + while (!__tpl_list_is_empty(wayland_egl_surface->attached_buffers)) { + tbm_surface_h tbm_surface = + __tpl_list_pop_front(wayland_egl_surface->attached_buffers, NULL); + tbm_surface_internal_unref(tbm_surface); + } + TPL_OBJECT_UNLOCK(&wayland_egl_surface->base); + } } static const struct tizen_surface_shm_flusher_listener -- 2.7.4