From 7513387589a725918d5ee47ff6458a3c46ef1756 Mon Sep 17 00:00:00 2001 From: "joonbum.ko" Date: Fri, 15 Dec 2017 17:36:06 +0900 Subject: [PATCH] tpl_wayland_egl_thread: Implemented sync_draw_source. - One sync_draw_source is created for each buffer which is enqueued to tbm_queue. - sync_draw_source will be attached to vk_sub_thread. - It is created when set sync_fence_fd and blocking waits in vk_sub_thread until fence is released. Change-Id: I1aba360f52a2c6d245bb52c34c42a465dacc5215 Signed-off-by: joonbum.ko --- src/tpl_wayland_egl_thread.c | 243 +++++++++++++++++++++++++++++++------------ src/tpl_wl_vk_thread.c | 5 +- 2 files changed, 178 insertions(+), 70 deletions(-) diff --git a/src/tpl_wayland_egl_thread.c b/src/tpl_wayland_egl_thread.c index d865a69..29f92a4 100644 --- a/src/tpl_wayland_egl_thread.c +++ b/src/tpl_wayland_egl_thread.c @@ -31,6 +31,7 @@ typedef struct _twe_wl_surf_source twe_wl_surf_source; typedef struct _twe_wl_buffer_info twe_wl_buffer_info; typedef struct _twe_tdm_source twe_tdm_source; typedef struct _twe_del_source twe_del_source; +typedef struct _vk_sync_draw_source twe_sync_draw_source; struct _twe_thread_context { GThread *twe_thread; @@ -120,6 +121,7 @@ struct _twe_wl_surf_source { GCond free_queue_cond; /* for waiting draw done */ + tpl_bool_t use_sync_fence; GThread *vk_sub_thread; GMainLoop *vk_sub_loop; }; @@ -144,17 +146,26 @@ struct _twe_wl_buffer_info { /* for checking draw done */ tpl_bool_t draw_done; - tbm_fd draw_done_fence; /* for checking released from display server */ tbm_fd sync_timeline; unsigned int sync_timestamp; + twe_sync_draw_source *sync_draw_source; tbm_surface_h tbm_surface; twe_wl_surf_source *surf_source; }; +struct _vk_sync_draw_source { + GSource gsource; + gpointer tag; + int event_fd; + int draw_done_signal_fd; + tbm_fd draw_fence_fd; + tbm_surface_h tbm_surface; + twe_wl_buffer_info *buf_info; +}; static twe_thread_context *_twe_ctx; static twe_tdm_source * @@ -1270,11 +1281,6 @@ __cb_twe_buffer_free_callback(twe_wl_buffer_info *buf_info) wl_display_flush(disp_source->disp); - if (buf_info->draw_done_fence != -1) { - close(buf_info->draw_done_fence); - buf_info->draw_done_fence = -1; - } - if (buf_info->wl_buffer) wayland_tbm_client_destroy_buffer(disp_source->wl_tbm_client, (void *)buf_info->wl_buffer); @@ -1462,7 +1468,6 @@ _twe_surface_set_wl_buffer_info(twe_wl_surf_source *surf_source, TPL_WARN("Failed to create TBM sync timeline: %d(%s)", errno, buf); } - buf_info->draw_done_fence = -1; buf_info->sync_timestamp = 0; buf_info->surf_source = surf_source; buf_info->num_rects = 0; @@ -1470,6 +1475,7 @@ _twe_surface_set_wl_buffer_info(twe_wl_surf_source *surf_source, buf_info->need_to_commit = TPL_TRUE; buf_info->draw_done = TPL_FALSE; buf_info->tbm_surface = tbm_surface; + buf_info->sync_draw_source = NULL; wl_buffer_add_listener((void *)buf_info->wl_buffer, &wl_buffer_release_listener, tbm_surface); @@ -1541,11 +1547,14 @@ __cb_tbm_queue_acquirable_callback(tbm_surface_queue_h surface_queue, uint64_t value = 1; int ret; - ret = write(surf_source->event_fd, &value, sizeof(uint64_t)); - if (ret == -1) { - TPL_ERR("failed to send acquirable event. twe_wl_surf_source(%p)", - surf_source); - return; + if (!surf_source->disp_source->is_vulkan_dpy + || !surf_source->use_sync_fence) { + ret = write(surf_source->event_fd, &value, sizeof(uint64_t)); + if (ret == -1) { + TPL_ERR("failed to send acquirable event. twe_wl_surf_source(%p)", + surf_source); + return; + } } } @@ -1658,46 +1667,6 @@ _twe_surface_wait_vblank(twe_wl_surf_source *surf_source) return TPL_ERROR_NONE; } -static tpl_result_t -_twe_surface_wait_draw_done(tbm_surface_h tbm_surface) -{ - twe_wl_buffer_info *buf_info = NULL; - - if (!tbm_surface || !tbm_surface_internal_is_valid(tbm_surface)) { - TPL_ERR("Invalid tbm_surface(%p)", tbm_surface); - return TPL_ERROR_INVALID_PARAMETER; - } - - tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO, - (void **)&buf_info); - if (!buf_info) { - TPL_ERR("Failed to get twe_wl_buffer_info from tbm_surface(%p)", - tbm_surface); - return TPL_ERROR_INVALID_OPERATION; - } - - if (buf_info->draw_done_fence == -1) { - TPL_WARN("tbm_surface(%p) will be presented immediately.", tbm_surface); - return TPL_ERROR_NONE; - } - - TRACE_BEGIN("Fence waiting. BO(%d)", - tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0))); - if (tbm_sync_fence_wait(buf_info->draw_done_fence, -1) != 1) { - char buf[1024]; - strerror_r(errno, buf, sizeof(buf)); - TPL_ERR("Failed to wait sync fence(%d). | error: %d(%s)", - buf_info->draw_done_fence, errno, buf); - } - TRACE_END(); - - close(buf_info->draw_done_fence); - buf_info->draw_done_fence = -1; - buf_info->draw_done = TPL_TRUE; - - return TPL_ERROR_NONE; -} - static void _twe_thread_wl_vk_surface_commit(twe_wl_surf_source *surf_source, tbm_surface_h tbm_surface) @@ -1882,12 +1851,6 @@ _twe_thread_wl_surface_acquire_and_commit(twe_wl_surf_source *surf_source) tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO, (void **)&buf_info); - if (!buf_info->draw_done && buf_info->draw_done_fence != -1) { - /* wait until draw done. */ - if (_twe_surface_wait_draw_done(tbm_surface) != TPL_ERROR_NONE) - TPL_ERR("Failed to wait drawing complete."); - } - if (!disp_source->is_vulkan_dpy) { /* wayland_egl */ TPL_LOG_T(BACKEND, "[ACQ] tbm_surface(%p) bo(%d)", tbm_surface, @@ -2316,6 +2279,7 @@ twe_surface_add(twe_thread* thread, source->cb_data = NULL; source->rotate_cb = NULL; source->format = format; + source->use_sync_fence = TPL_FALSE; /* for vulkan swapchain */ source->vblank_waiting_buffers = NULL; @@ -2686,33 +2650,178 @@ twe_surface_commit_without_enqueue(twe_surface_h twe_surface, TPL_OBJECT_UNLOCK(&surf_source->obj); } +static gboolean +_twe_thread_sync_draw_source_dispatch(GSource *source, GSourceFunc cb, gpointer data) +{ + twe_sync_draw_source *sync_draw_source = (twe_sync_draw_source *)source; + GIOCondition cond; + + if (g_source_is_destroyed(source)) { + TPL_ERR("del_source(%p) already destroyed.", source); + return G_SOURCE_REMOVE; + } + + cond = g_source_query_unix_fd(source, sync_draw_source->tag); + + if (cond & G_IO_IN) { + ssize_t s; + uint64_t u; + int ret; + uint64_t value = 1; + tbm_surface_h tbm_surface = sync_draw_source->tbm_surface; + + tbm_surface_internal_ref(tbm_surface); + + s = read(sync_draw_source->event_fd, &u, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) + TPL_ERR("Failed to read from event_fd(%d)", + sync_draw_source->event_fd); + + TRACE_BEGIN("Fence waiting. BO(%d)", + tbm_bo_export( + tbm_surface_internal_get_bo(tbm_surface, 0))); + + /* Below API is blocking call. + * It is waiting for drawing complete in GPU. */ + if (tbm_sync_fence_wait(sync_draw_source->draw_fence_fd, -1) != 1) { + char buf[1024]; + strerror_r(errno, buf, sizeof(buf)); + TPL_ERR("Failed to wait sync fence(%d). | error: %d(%s)", + sync_draw_source->draw_fence_fd, errno, buf); + } + + /* Draw done */ + /* Send event to twe_wl_surf_source */ + ret = write(sync_draw_source->draw_done_signal_fd, + &value, sizeof(uint64_t)); + if (ret == -1) { + TPL_ERR("failed to send acquirable event. tbm_surface(%p)", + tbm_surface); + return G_SOURCE_REMOVE; + } + TRACE_END(); + + tbm_surface_internal_unref(tbm_surface); + } + + return G_SOURCE_REMOVE; +} + +static void +_twe_thread_sync_draw_source_finalize(GSource *source) +{ + twe_sync_draw_source *sync_draw_source = (twe_sync_draw_source *)source; + twe_wl_buffer_info *buf_info = sync_draw_source->buf_info; + + TPL_LOG_T(BACKEND, "gsource(%p) event_fd(%d)", + source, sync_draw_source->event_fd); + + close(sync_draw_source->event_fd); + + buf_info->sync_draw_source = NULL; + sync_draw_source->tag = NULL; + sync_draw_source->event_fd = -1; + sync_draw_source->draw_done_signal_fd = -1; + sync_draw_source->buf_info = NULL; + sync_draw_source->tbm_surface = NULL; + + return; +} + +static GSourceFuncs _twe_sync_draw_source_funcs = { + .prepare = NULL, + .check = NULL, + .dispatch = _twe_thread_sync_draw_source_dispatch, + .finalize = _twe_thread_sync_draw_source_finalize, +}; + +static twe_sync_draw_source * +_twe_sync_draw_source_attach(twe_wl_surf_source *surf_source, + twe_wl_buffer_info *buf_info, + tbm_fd sync_fd) +{ + twe_sync_draw_source *source = NULL; + + if (!surf_source->vk_sub_thread || !surf_source->vk_sub_loop) { + TPL_ERR("Invalid parameter. vk_sub_thread is not initialized."); + return NULL; + } + + if (!buf_info) { + TPL_ERR("Invalid parameter. buf_info is NULL"); + return NULL; + } + + source = (twe_sync_draw_source *)g_source_new(&_twe_sync_draw_source_funcs, + sizeof(twe_sync_draw_source)); + if (!source) { + TPL_ERR("[THREAD] Failed to create GSource"); + return NULL; + } + + source->event_fd = eventfd(0, EFD_CLOEXEC); + if (source->event_fd < 0) { + TPL_ERR("[THREAD] Failed to create eventfd. errno(%d)", errno); + g_source_unref(&source->gsource); + return NULL; + } + + source->tag = g_source_add_unix_fd(&source->gsource, + source->event_fd, + G_IO_IN); + source->draw_done_signal_fd = surf_source->event_fd; + source->draw_fence_fd = sync_fd; + source->buf_info = buf_info; + source->tbm_surface = buf_info->tbm_surface; + + g_source_attach(&source->gsource, g_main_loop_get_context(surf_source->vk_sub_loop)); + g_source_unref(&source->gsource); + + return source; +} + tpl_result_t twe_surface_set_sync_fd(twe_surface_h twe_surface, tbm_surface_h tbm_surface, tbm_fd sync_fd) { + twe_wl_surf_source *surf_source = (twe_wl_surf_source *)twe_surface; twe_wl_buffer_info *buf_info = NULL; - - /* TODO : It will be used at soon */ - TPL_IGNORE(twe_surface); + twe_sync_draw_source *sync_draw_source = NULL; + int ret; + uint64_t value = 1; tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO, (void **)&buf_info); if (!buf_info) { TPL_ERR("wl_buffer_info is not existed in tbm_surface(%p)", tbm_surface); + surf_source->use_sync_fence = TPL_FALSE; return TPL_ERROR_INVALID_OPERATION; } - if (sync_fd == -1) { - TPL_WARN("It will be managed with async mode."); + sync_draw_source = _twe_sync_draw_source_attach(surf_source, + buf_info, sync_fd); + if (!sync_draw_source) { + TPL_ERR("Failed to create and attach sync_draw_source."); + surf_source->use_sync_fence = TPL_FALSE; + return TPL_ERROR_INVALID_OPERATION; } - if (buf_info->draw_done_fence != -1) { - close(buf_info->draw_done_fence); - buf_info->draw_done_fence = -1; + /* Draw done */ + /* Send event to twe_wl_surf_source */ + ret = write(sync_draw_source->event_fd, + &value, sizeof(uint64_t)); + if (ret == -1) { + TPL_ERR("failed to send acquirable event. twe_wl_surf_source(%p)", + surf_source); + g_source_remove_unix_fd(&sync_draw_source->gsource, sync_draw_source->tag); + g_source_destroy(&sync_draw_source->gsource); + g_source_unref(&sync_draw_source->gsource); + surf_source->use_sync_fence = TPL_FALSE; + return TPL_ERROR_INVALID_OPERATION; } - buf_info->draw_done_fence = sync_fd; + surf_source->use_sync_fence = TPL_TRUE; return TPL_ERROR_NONE; } diff --git a/src/tpl_wl_vk_thread.c b/src/tpl_wl_vk_thread.c index 527ee3a..b1eaf75 100644 --- a/src/tpl_wl_vk_thread.c +++ b/src/tpl_wl_vk_thread.c @@ -358,9 +358,8 @@ __tpl_wl_vk_wsi_surface_enqueue_buffer(tpl_surface_t *surface, res = twe_surface_set_sync_fd(wayland_vk_wsi_surface->twe_surface, tbm_surface, sync_fence); if (res != TPL_ERROR_NONE) { - TPL_ERR("Failed to set sync_fd to tbm_surface(%p)", tbm_surface); - tbm_surface_internal_unref(tbm_surface); - return res; + TPL_WARN("Failed to set sync_fd(%d). Fallback to async mode.", + sync_fence); } } -- 2.7.4