tpl_wayland_egl_thread: Implemented the presentation sync feature. 50/219550/1
authorJoonbum Ko <joonbum.ko@samsung.com>
Thu, 14 Nov 2019 10:31:42 +0000 (19:31 +0900)
committerJoonbum Ko <joonbum.ko@samsung.com>
Fri, 6 Dec 2019 01:55:18 +0000 (10:55 +0900)
 - Create a timeline in surface and create a sync fence to pass to the user.
 - The sync fence user get is signaled at the time of presentation done.
 - This feature can help user sync by telling presentation done.
   Users should handle this sync_fence properly using poll or select.

 - This patch depends on wayland-extension and enlightenment.

Change-Id: I180ac6b23cc89ed3f7f0ebfc934893efa873dd6a
Signed-off-by: Joonbum Ko <joonbum.ko@samsung.com>
configure.ac
packaging/libtpl-egl.spec
src/tpl_wayland_egl_thread.c

index 077366e..7a761bb 100644 (file)
@@ -60,7 +60,7 @@ AC_ARG_WITH([wayland],
    [with_wayland=yes])
 
 AS_IF([test "${with_wayland}" = "yes" || test "${with_wayland}" = "1"],
-         [PKG_CHECK_MODULES([TPL_WL], [libtdm-client wayland-tbm-client wayland-tbm-server tizen-surface-client glib-2.0 wayland-egl wayland-egl-backend])
+         [PKG_CHECK_MODULES([TPL_WL], [libtdm-client wayland-tbm-client wayland-tbm-server tizen-surface-client glib-2.0 wayland-egl presentation-time-client wayland-egl-backend])
           TPL_CFLAGS+="$TPL_WL_CFLAGS"
           TPL_CFLAGS+=" -DTPL_WINSYS_WL=1 "
           TPL_LIBS+="$TPL_WL_LIBS"],
index 7b4b3eb..b49148a 100644 (file)
@@ -79,6 +79,7 @@ BuildRequires:        pkgconfig(wayland-egl-backend)
 BuildRequires: pkgconfig(wayland-tbm-client)
 BuildRequires: pkgconfig(wayland-tbm-server)
 BuildRequires: pkgconfig(tizen-surface-client)
+BuildRequires:  pkgconfig(presentation-time-client)
 BuildRequires: pkgconfig(glib-2.0)
 %endif
 
index 101cf8f..f7fb447 100755 (executable)
@@ -10,6 +10,7 @@
 #include <glib-unix.h>
 #include <tizen-surface-client-protocol.h>
 #include <wayland-egl-backend.h>
+#include <presentation-time-client-protocol.h>
 
 #include "tpl_utils.h"
 #include "tpl_internal.h"
@@ -67,6 +68,7 @@ struct _twe_wl_disp_source {
        struct wl_event_queue *ev_queue;
        struct wayland_tbm_client *wl_tbm_client;
        struct tizen_surface_shm *tss; /* used for surface buffer_flush */
+       struct wp_presentation *presentation;
        struct {
                int min_buffer;
                int max_buffer;
@@ -125,6 +127,12 @@ struct _twe_wl_surf_source {
        int render_sync_timestamp;
        unsigned int render_sync_fence_number;
 
+       tbm_fd presentation_sync_timeline;
+       int presentation_sync_timestamp;
+       int presentation_sync_ts_backup;
+       int presentation_sync_req_cnt;
+       GMutex pst_mutex;
+
        GMutex surf_mutex;
 
        GMutex free_queue_mutex;
@@ -788,6 +796,13 @@ __cb_wl_resistry_global_callback(void *data, struct wl_registry *wl_registry,
                                                         &wayland_vulkan_interface,
                                                         version);
        }
+
+       if (!strcmp(interface, wp_presentation_interface.name)) {
+               disp_source->presentation =
+                       wl_registry_bind(wl_registry,
+                                        name, &wp_presentation_interface, 1);
+               TPL_DEBUG("bind wp_presentation_interface");
+       }
 }
 
 void
@@ -867,6 +882,12 @@ _twe_display_wayland_init(twe_wl_disp_source *disp_source)
                TPL_LOG_T(BACKEND, "wl_vk_client(%p) init.", disp_source->wl_vk_client);
        }
 
+       if (disp_source->presentation) {
+               wl_proxy_set_queue((struct wl_proxy *)disp_source->presentation,
+                                                  disp_source->ev_queue);
+               TPL_LOG_T(BACKEND, "wp_presentation(%p) init.", disp_source->presentation);
+       }
+
 fini:
        if (display_wrapper)
                wl_proxy_wrapper_destroy(display_wrapper);
@@ -1261,6 +1282,44 @@ __cb_create_render_sync_fd(struct wl_egl_window *wl_egl_window, void *private)
        return -1;
 }
 
+static int
+__cb_create_presentation_sync_fd(struct wl_egl_window *wl_egl_window, void *private)
+{
+       TPL_ASSERT(private);
+       TPL_ASSERT(wl_egl_window);
+
+       struct tizen_private *tizen_private = (struct tizen_private *)private;
+       twe_wl_surf_source *surf_source = NULL;
+
+       tbm_fd presentation_sync_fd = -1;
+
+       surf_source = (twe_wl_surf_source *)tizen_private->data;
+       if (!surf_source) {
+               TPL_ERR("Invalid parameter. twe_surface(%p)", surf_source);
+               return -1;
+       }
+
+       if (surf_source->presentation_sync_timeline != -1) {
+               g_mutex_lock(&surf_source->pst_mutex);
+
+               presentation_sync_fd = tbm_sync_fence_create(surf_source->presentation_sync_timeline,
+                                                                                          NULL,
+                                                                                          surf_source->presentation_sync_timestamp++);
+               TPL_DEBUG("[PRESENTATION_SYNC] surf_source(%p) timeline(%d) timestamp(%d) sync_fence(%d)",
+                                 surf_source, surf_source->presentation_sync_timeline, surf_source->presentation_sync_timestamp,
+                                 presentation_sync_fd);
+
+               TRACE_ASYNC_BEGIN(surf_source->presentation_sync_timestamp, "[PRESENTATION]");
+
+               surf_source->presentation_sync_req_cnt++;
+
+               g_mutex_unlock(&surf_source->pst_mutex);
+               return presentation_sync_fd;
+       }
+
+       return -1;
+}
+
 
 static void __cb_tss_flusher_flush_callback(void *data,
                struct tizen_surface_shm_flusher *tss_flusher)
@@ -1901,6 +1960,105 @@ _twe_thread_wl_vk_surface_commit(twe_wl_surf_source *surf_source,
 }
 
 static void
+__cb_presentation_feedback_sync_output(void *data,
+                    struct wp_presentation_feedback *presentation_feedback,
+                    struct wl_output *output)
+{
+       TPL_IGNORE(data);
+       TPL_IGNORE(presentation_feedback);
+       TPL_IGNORE(output);
+}
+
+static void
+__cb_presentation_feedback_presented(void *data,
+                       struct wp_presentation_feedback *presentation_feedback,
+                       uint32_t tv_sec_hi,
+                       uint32_t tv_sec_lo,
+                       uint32_t tv_nsec,
+                       uint32_t refresh_nsec,
+                       uint32_t seq_hi,
+                       uint32_t seq_lo,
+                       uint32_t flags)
+{
+       TPL_IGNORE(tv_sec_hi);
+       TPL_IGNORE(tv_sec_lo);
+       TPL_IGNORE(tv_nsec);
+       TPL_IGNORE(refresh_nsec);
+       TPL_IGNORE(seq_hi);
+       TPL_IGNORE(seq_lo);
+       TPL_IGNORE(flags);
+
+       twe_wl_surf_source *surf_source = (twe_wl_surf_source *)data;
+
+       g_mutex_lock(&surf_source->pst_mutex);
+
+       TPL_DEBUG("[FEEDBACK][PRESENTED] surf_source(%p) wl_surface(%p)",
+                         surf_source, surf_source->surf);
+
+       if (surf_source->presentation_sync_timeline != -1 &&
+               surf_source->presentation_sync_req_cnt > 0) {
+
+               surf_source->presentation_sync_ts_backup++;
+               surf_source->presentation_sync_req_cnt--;
+
+               TRACE_ASYNC_END(surf_source->presentation_sync_ts_backup, "[PRESENTATION]");
+
+               TPL_DEBUG("[PRESENTATION][INC] surf_source(%p) timeline(%d) timestamp(%d)",
+                                 surf_source, surf_source->presentation_sync_timeline,
+                                 surf_source->presentation_sync_ts_backup);
+               if (!tbm_sync_timeline_inc(surf_source->presentation_sync_timeline, 1)) {
+                       TPL_ERR("Failed to increase timeline(%d)",
+                                       surf_source->presentation_sync_timeline);
+               }
+       }
+
+       if (presentation_feedback)
+               wp_presentation_feedback_destroy(presentation_feedback);
+
+       g_mutex_unlock(&surf_source->pst_mutex);
+}
+
+static void
+__cb_presentation_feedback_discarded(void *data,
+                       struct wp_presentation_feedback *presentation_feedback)
+{
+       twe_wl_surf_source *surf_source = (twe_wl_surf_source *)data;
+
+       g_mutex_lock(&surf_source->pst_mutex);
+
+       TPL_DEBUG("[FEEDBACK][DISCARDED] surf_source(%p) wl_surface(%p)",
+                         surf_source, surf_source->surf);
+
+       if (surf_source->presentation_sync_timeline != -1 &&
+               surf_source->presentation_sync_req_cnt > 0) {
+
+               surf_source->presentation_sync_ts_backup++;
+               surf_source->presentation_sync_req_cnt--;
+
+               TRACE_ASYNC_END(surf_source->presentation_sync_ts_backup, "[PRESENTATION]");
+
+               TPL_DEBUG("[PRESENTATION][INC] surf_source(%p) timeline(%d) timestamp(%d)",
+                                 surf_source, surf_source->presentation_sync_timeline,
+                                 surf_source->presentation_sync_ts_backup);
+               if (!tbm_sync_timeline_inc(surf_source->presentation_sync_timeline, 1)) {
+                       TPL_ERR("Failed to increase timeline(%d)",
+                                       surf_source->presentation_sync_timeline);
+               }
+       }
+
+       if (presentation_feedback)
+               wp_presentation_feedback_destroy(presentation_feedback);
+
+       g_mutex_unlock(&surf_source->pst_mutex);
+}
+
+static const struct wp_presentation_feedback_listener feedback_listener = {
+       __cb_presentation_feedback_sync_output, /* sync_output feedback -*/
+       __cb_presentation_feedback_presented,
+       __cb_presentation_feedback_discarded
+};
+
+static void
 _twe_thread_wl_surface_commit(twe_wl_surf_source *surf_source,
                                                          tbm_surface_h tbm_surface)
 {
@@ -1909,6 +2067,7 @@ _twe_thread_wl_surface_commit(twe_wl_surf_source *surf_source,
        struct wl_surface *wl_surface = surf_source->surf;
        struct wl_egl_window *wl_egl_window = surf_source->wl_egl_window;
        uint32_t version;
+       struct wp_presentation_feedback *p_feedback;
 
        tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO,
                                                                           (void **)&buf_info);
@@ -1920,6 +2079,15 @@ _twe_thread_wl_surface_commit(twe_wl_surf_source *surf_source,
 
        version = wl_proxy_get_version((struct wl_proxy *)wl_surface);
 
+       g_mutex_lock(&surf_source->pst_mutex);
+       if (disp_source->presentation &&
+               surf_source->presentation_sync_req_cnt > 0) {
+               p_feedback = wp_presentation_feedback(disp_source->presentation,
+                                                                                         wl_surface);
+               wp_presentation_feedback_add_listener(p_feedback, &feedback_listener, surf_source);
+       }
+       g_mutex_unlock(&surf_source->pst_mutex);
+
        if (buf_info->w_rotated == TPL_TRUE) {
                wayland_tbm_client_set_buffer_transform(
                                disp_source->wl_tbm_client,
@@ -2558,6 +2726,11 @@ twe_surface_add(twe_thread* thread,
        source->render_sync_timestamp = 0;
        source->render_sync_fence_number = 0;
 
+       source->presentation_sync_timeline = tbm_sync_timeline_create();
+       source->presentation_sync_timestamp = 0;
+       source->presentation_sync_ts_backup = 0;
+       source->presentation_sync_req_cnt = 0;
+
        if (!disp_source->is_vulkan_dpy) {
                struct wl_egl_window *wl_egl_window =
                        (struct wl_egl_window *)native_handle;
@@ -2578,6 +2751,7 @@ twe_surface_add(twe_thread* thread,
                        private->set_window_serial_callback = (void *)
                                __cb_set_window_serial_callback;
                        private->create_render_sync_fd = (void *)__cb_create_render_sync_fd;
+                       private->create_presentation_sync_fd = (void *)__cb_create_presentation_sync_fd;
 
                        source->latest_transform = private->transform;
 
@@ -2607,6 +2781,7 @@ twe_surface_add(twe_thread* thread,
        g_source_attach(&source->gsource, g_main_loop_get_context(ctx->twe_loop));
 
        g_mutex_init(&source->surf_mutex);
+       g_mutex_init(&source->pst_mutex);
 
        g_mutex_init(&source->free_queue_mutex);
        g_cond_init(&source->free_queue_cond);