add e_explicit_sync for supporting zwp_linux_explicit_synchronization sandbox/cyeon/devel
authorChangyeon Lee <cyeon.lee@samsung.com>
Wed, 1 Jul 2020 10:31:51 +0000 (19:31 +0900)
committerChangyeon Lee <cyeon.lee@samsung.com>
Wed, 1 Jul 2020 10:43:31 +0000 (19:43 +0900)
Change-Id: Ie79f995c41572bf2652f94df9c87013df659a100

18 files changed:
configure.ac
packaging/enlightenment.spec
src/bin/Makefile.mk
src/bin/e_client.h
src/bin/e_comp_screen.c
src/bin/e_comp_wl.c
src/bin/e_comp_wl.h
src/bin/e_explicit_sync.c [new file with mode: 0644]
src/bin/e_explicit_sync.h [new file with mode: 0644]
src/bin/e_hwc.c
src/bin/e_hwc.h
src/bin/e_hwc_window.c
src/bin/e_hwc_window.h
src/bin/e_hwc_windows.c
src/bin/e_includes.h
src/bin/e_info_client.c
src/bin/e_info_server.c
src/bin/e_info_shared_types.h

index 235db3e745cc48ca84a9ee314408e91689758d6a..7d69f8bc49ac8a08b22d0eee71347b9176811d0a 100755 (executable)
@@ -369,7 +369,7 @@ AC_MSG_RESULT([${have_shm_open}])
 AC_SUBST(SHM_OPEN_LIBS)
 
 if test "x${e_cv_want_wayland_only}" != "xno" || test "x${e_cv_want_wayland_clients}" != "xno";then
-  PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server tizen-hwc-server],
+  PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server tizen-hwc-server linux-explicit-synchronization-unstable-v1-server],
     [
       have_wayland=yes
       AC_DEFINE_UNQUOTED([HAVE_WAYLAND],[1],[enable wayland support])
index e79a82eef522323495d4e248856d092f834db6e6..c936a7bb95f249c9fc9ca0fd7a5d5ba5dec58248 100644 (file)
@@ -55,6 +55,7 @@ BuildRequires:  systemd-devel
 BuildRequires:  pkgconfig(libinput)
 BuildRequires:  pkgconfig(presentation-time-server)
 BuildRequires:  pkgconfig(egl)
+BuildRequires:  pkgconfig(linux-explicit-synchronization-unstable-v1-server)
 BuildRequires:  pkgconfig(tizen-hwc-server)
 Requires:       libwayland-extension-server
 
index 8c826de236d71d89dbfb48e6245a6e495b1ec2a8..5c7e09cff7da9c8765bdae36e2f81c5ea5de80af 100644 (file)
@@ -97,6 +97,7 @@ src/bin/e_hwc_planes.h \
 src/bin/e_hwc_windows.h \
 src/bin/e_hwc_window.h \
 src/bin/e_hwc_window_queue.h \
+src/bin/e_explicit_sync.h \
 src/bin/e_egl_sync.h \
 src/bin/e_info_server_input.h
 
@@ -220,6 +221,7 @@ src/bin/e_hwc_planes.c \
 src/bin/e_hwc_windows.c \
 src/bin/e_hwc_window.c \
 src/bin/e_hwc_window_queue.c \
+src/bin/e_explicit_sync.c \
 src/bin/e_egl_sync.c \
 src/bin/e_info_server_input.c \
 $(ENLIGHTENMENTHEADERS)
index c683a04770e6daa74f8b971fa3ba1d8f9d3f3999..d19e089dc826a7206efcf35ed0505410e12ac791 100644 (file)
@@ -969,6 +969,7 @@ struct E_Client
    Eina_Bool skip_save_img: 1; // indicates that window doesn't want to save its image file
 
    E_Hwc_Window *hwc_window; // hwc window for the tdm_hwc.
+   E_Explicit_Sync_Surface *explicit_sync_surface;
    int comp_override;
 
    struct
index cc857b524617ea73d5daf1ff4d02284053ee57f0..2dbf3fa142772da78154bbd2920c6515f225e37a 100644 (file)
@@ -653,6 +653,7 @@ _e_comp_screen_deinit_outputs(E_Comp_Screen *e_comp_screen)
         e_output_del(output);
      }
 
+   e_explicit_sync_deinit();
    e_egl_sync_deinit();
    e_hwc_deinit();
    e_hwc_windows_deinit();
@@ -1107,6 +1108,11 @@ e_comp_screen_init()
      ELOGF("E_EGL_SYNC", "Enabled the E_Egl_Sync", NULL);
    e_main_ts_end("\tE_Egl_Sync Init Done");
 
+   e_main_ts_begin("\tE_Explicit_Sync Init");
+   if (e_explicit_sync_init())
+     ELOGF("EX-SYNC", "Enabled the E_Explicit_Sync", NULL);
+   e_main_ts_end("\tE_Explicit_Sync Init Done");
+
    /* pointer */
    e_input_device_pointer_xy_get(NULL, &ptr_x, &ptr_y);
    e_comp_wl->ptr.x = wl_fixed_from_int(ptr_x);
index 48653e50a5e7dbc739ffe1ec247d719a25d822af..1537d050773c4920656f1c16e293830cbafbb5e8 100644 (file)
@@ -4291,6 +4291,9 @@ e_comp_wl_surface_commit(E_Client *ec)
           e_pixmap_image_clear(ec->pixmap, 1);
      }
 
+   if (ec->explicit_sync_surface)
+     e_explicit_sync_surface_commit(ec->explicit_sync_surface);
+
    ignored = ec->ignored;
 
    if (e_comp_wl_subsurface_order_commit(ec))
@@ -4375,6 +4378,12 @@ e_comp_wl_buffer_reference(E_Comp_Wl_Buffer_Ref *ref, E_Comp_Wl_Buffer *buffer)
         ref->buffer->busy--;
         if (ref->buffer->busy == 0)
           {
+             if (ref->buffer->buffer_release)
+               {
+                  e_explicit_sync_buffer_release_destroy(ref->buffer->buffer_release);
+                  ref->buffer->buffer_release = NULL;
+               }
+
              if (ref->buffer->resource)
                {
                   if (!wl_resource_get_client(ref->buffer->resource)) return;
index c0d21439ad7c4fca3c83a01178d41a5863ca481a..ac95bd0140534e9daaf78e47770bfe3b51d1a414 100644 (file)
@@ -118,6 +118,8 @@ struct _E_Comp_Wl_Buffer
    int32_t w, h;
    int transform; // the value of wl_tbm.set_buffer_transform
    uint32_t busy;
+
+   E_Explicit_Sync_Buffer_Release *buffer_release;
 };
 
 struct _E_Comp_Wl_Buffer_Ref
diff --git a/src/bin/e_explicit_sync.c b/src/bin/e_explicit_sync.c
new file mode 100644 (file)
index 0000000..916b78a
--- /dev/null
@@ -0,0 +1,550 @@
+#include "e.h"
+#include <linux-explicit-synchronization-unstable-v1-server-protocol.h>
+#include <tizen-extension-server-protocol.h>
+
+#define EX_SYNC_TRACE(f, ec, x... )                              \
+   do                                                            \
+     {                                                           \
+        if (ex_sync_trace)                                       \
+          {                                                      \
+             if (ec)                                             \
+               {                                                 \
+                  INF("EWL|%20.20s|w:0x%08zx|ec:%8p|"f,          \
+                      "EX-SYNC",                                 \
+                      (e_client_util_win_get(ec)),               \
+                      (ec),                                      \
+                      ##x);                                      \
+               }                                                 \
+             else                                                \
+               {                                                 \
+                  INF("EWL|%20.20s|            |             |"f,\
+                      "EX-SYNC",##x);                            \
+               }                                                 \
+          }                                                      \
+      }                                                          \
+   while (0)
+
+static E_Explicit_Sync *_explicit_sync = NULL;
+static Eina_Bool _explicit_sync_enabled = EINA_FALSE;
+static Eina_Bool ex_sync_trace = EINA_FALSE;
+
+static E_Comp_Wl_Buffer *
+_e_explicit_sync_comp_wl_buffer_get(E_Client *ec)
+{
+   E_Comp_Client_Data *cdata;
+
+   if (!ec) return NULL;
+
+   cdata = ec->comp_data;
+   if (!cdata) return NULL;
+
+   return cdata->buffer_ref.buffer;
+}
+
+static Eina_Bool
+_e_explicit_sync_fd_is_valid(int fd)
+{
+   /* need sync file check */
+   return EINA_TRUE;
+}
+
+static void
+_e_explicit_sync_fd_set(int *fd, int new_fd)
+{
+   if (*fd == new_fd) return;
+
+   if (*fd >= 0) close(*fd);
+   *fd = new_fd;
+}
+
+static void
+_e_explicit_sync_fd_clear(int* fd)
+{
+   _e_explicit_sync_fd_set(fd, -1);
+}
+
+static void
+_e_explicit_sync_fd_move(int *dst, int *src)
+{
+   if (dst == src) return;
+
+   _e_explicit_sync_fd_set(dst, *src);
+   *src = -1;
+}
+
+static void
+_e_explicit_sync_surface_cb_destroy(struct wl_client *client,
+                                    struct wl_resource *resource)
+{
+   wl_resource_destroy(resource);
+}
+
+static void
+_e_explicit_sync_surface_cb_set_acquire_fence(struct wl_client *client,
+                                              struct wl_resource *resource,
+                                              int32_t fd)
+{
+   E_Explicit_Sync_Surface *explicit_sync_surface;
+
+   explicit_sync_surface = wl_resource_get_user_data(resource);
+   if (!explicit_sync_surface)
+     {
+        wl_resource_post_error(resource,
+                               ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_SURFACE,
+                               "surface no longer exists");
+        goto fail;
+     }
+
+   if (!_e_explicit_sync_fd_is_valid(fd))
+     {
+        wl_resource_post_error(resource,
+                               ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_INVALID_FENCE,
+                               "invalid acquire fence fd");
+        goto fail;
+     }
+
+   if (explicit_sync_surface->pending_acquire_fence_fd != -1)
+     {
+        wl_resource_post_error(resource,
+                               ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_DUPLICATE_FENCE,
+                               "exist acquire fence fd");
+        goto fail;
+     }
+
+   _e_explicit_sync_fd_set(&explicit_sync_surface->pending_acquire_fence_fd, fd);
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Set Acquire fence fd:%d",
+                 explicit_sync_surface->ec, explicit_sync_surface, fd);
+
+   return;
+
+fail:
+   close(fd);
+}
+
+static void
+_e_explicit_sync_buffer_release_cb_resource_destroy(struct wl_resource *resource)
+{
+   E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release;
+
+   explicit_sync_buffer_release = wl_resource_get_user_data(resource);
+   if (!explicit_sync_buffer_release) return;
+
+   EX_SYNC_TRACE("Explicit_Sync Buffer_Release:%p Destroy", NULL, explicit_sync_buffer_release);
+
+   if (explicit_sync_buffer_release->fence_fd != -1)
+     _e_explicit_sync_fd_clear(&explicit_sync_buffer_release->fence_fd);
+
+   E_FREE(explicit_sync_buffer_release);
+}
+
+EINTERN void
+e_explicit_sync_buffer_release_destroy(E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release)
+{
+   EINA_SAFETY_ON_NULL_RETURN(explicit_sync_buffer_release);
+   EINA_SAFETY_ON_NULL_RETURN(explicit_sync_buffer_release->resource);
+
+   if (explicit_sync_buffer_release->fence_fd != -1)
+     {
+        zwp_linux_buffer_release_v1_send_fenced_release(explicit_sync_buffer_release->resource,
+                                                        explicit_sync_buffer_release->fence_fd);
+
+        EX_SYNC_TRACE("Explicit_Sync Buffer_Release:%p Release fence:%d",
+                      NULL, explicit_sync_buffer_release, explicit_sync_buffer_release->fence_fd);
+     }
+   else
+     {
+        zwp_linux_buffer_release_v1_send_immediate_release(explicit_sync_buffer_release->resource);
+
+        EX_SYNC_TRACE("Explicit_Sync Buffer_Release:%p Immediate Release", NULL, explicit_sync_buffer_release);
+     }
+
+   wl_resource_destroy(explicit_sync_buffer_release->resource);
+}
+
+EINTERN Eina_Bool
+e_explicit_sync_buffer_release_fence_fd_set(E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release,
+                                            int fence_fd)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync_buffer_release, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync_buffer_release->resource, EINA_FALSE);
+
+   if (explicit_sync_buffer_release->fence_fd != -1)
+     _e_explicit_sync_fd_clear(&explicit_sync_buffer_release->fence_fd);
+
+   explicit_sync_buffer_release->fence_fd = fence_fd;
+
+   EX_SYNC_TRACE("Explicit_Sync Buffer_Release:%p Set fence:%d",
+                 NULL, explicit_sync_buffer_release, explicit_sync_buffer_release->fence_fd);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_explicit_sync_surface_cb_get_release(struct wl_client *client,
+                                        struct wl_resource *resource,
+                                        uint32_t id)
+{
+   E_Explicit_Sync_Surface *explicit_sync_surface = NULL;
+   E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release = NULL;
+
+   explicit_sync_surface = wl_resource_get_user_data(resource);
+   if ((!explicit_sync_surface) ||
+       (!explicit_sync_surface->ec) ||
+       (e_object_is_del(E_OBJECT(explicit_sync_surface->ec))))
+     {
+        wl_resource_post_error(resource,
+                               ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_SURFACE,
+                               "explicit_sync_surface is already destroyed");
+        goto fail;
+     }
+
+   if (explicit_sync_surface->pending_buffer_release)
+     {
+         wl_resource_post_error(resource,
+                                ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_DUPLICATE_RELEASE,
+                                "already has a buffer release");
+         goto fail;
+     }
+
+   explicit_sync_buffer_release = E_NEW(E_Explicit_Sync_Buffer_Release, 1);
+   if (!explicit_sync_buffer_release)
+     {
+        wl_client_post_no_memory(client);
+        goto fail;
+     }
+
+   explicit_sync_buffer_release->fence_fd = -1;
+   explicit_sync_buffer_release->resource = wl_resource_create(client,
+                                                               &zwp_linux_buffer_release_v1_interface,
+                                                               wl_resource_get_version(resource),
+                                                               id);
+   if (!explicit_sync_buffer_release->resource)
+     {
+        wl_client_post_no_memory(client);
+        goto fail;
+     }
+
+   wl_resource_set_implementation(explicit_sync_buffer_release->resource,
+                                  NULL,
+                                  explicit_sync_buffer_release,
+                                  _e_explicit_sync_buffer_release_cb_resource_destroy);
+
+   explicit_sync_surface->pending_buffer_release = explicit_sync_buffer_release;
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Buffer_Release:%p Create",
+                 explicit_sync_surface->ec, explicit_sync_surface, explicit_sync_buffer_release);
+
+   return;
+
+fail:
+   if (explicit_sync_buffer_release)
+     E_FREE(explicit_sync_buffer_release);
+}
+
+static const struct zwp_linux_surface_synchronization_v1_interface _e_explicit_sync_surface_implementation = {
+   _e_explicit_sync_surface_cb_destroy,
+   _e_explicit_sync_surface_cb_set_acquire_fence,
+   _e_explicit_sync_surface_cb_get_release
+};
+
+static void
+_e_explicit_sync_surface_cb_ec_free(void *data, void *obj)
+{
+   E_Client *ec = (E_Client *)obj;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   if (!ec->explicit_sync_surface) return;
+
+   ec->explicit_sync_surface->ec_delfn = NULL;
+   ec->explicit_sync_surface->ec = NULL;
+}
+
+static void
+_e_explicit_sync_surface_cb_resource_destroy(struct wl_resource *resource)
+{
+   E_Explicit_Sync_Surface *explicit_sync_surface;
+
+   explicit_sync_surface = wl_resource_get_user_data(resource);
+   if (!explicit_sync_surface) return;
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Destroy", explicit_sync_surface->ec, explicit_sync_surface);
+
+   if (explicit_sync_surface->pending_acquire_fence_fd != -1)
+     _e_explicit_sync_fd_clear(&explicit_sync_surface->pending_acquire_fence_fd);
+
+   if (explicit_sync_surface->acquire_fence_fd != -1)
+     _e_explicit_sync_fd_clear(&explicit_sync_surface->acquire_fence_fd);
+
+   if (explicit_sync_surface->ec)
+     {
+        e_object_delfn_del(E_OBJECT(explicit_sync_surface->ec), explicit_sync_surface->ec_delfn);
+        explicit_sync_surface->ec_delfn = NULL;
+        explicit_sync_surface->ec = NULL;
+     }
+
+   E_FREE(explicit_sync_surface);
+}
+
+static void _e_explicit_sync_cb_get_synchronization(struct wl_client *client,
+                                                    struct wl_resource *resource,
+                                                    uint32_t id,
+                                                    struct wl_resource *surface)
+{
+   E_Client *ec;
+   E_Explicit_Sync_Surface *explicit_sync_surface = NULL;
+
+   ec = wl_resource_get_user_data(surface);
+   if ((!ec) || (e_object_is_del(E_OBJECT(ec))))
+     {
+        wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+                               "invalid wl_surface resource:%u",
+                               (unsigned int)wl_resource_get_id(surface));
+        goto fail;
+     }
+
+   if (ec->explicit_sync_surface)
+     {
+        wl_resource_post_error(resource,
+                               ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_V1_ERROR_SYNCHRONIZATION_EXISTS,
+                               "wl_surface resource:%u already has synchronization",
+                               (unsigned int)wl_resource_get_id(surface));
+        goto fail;
+     }
+
+   explicit_sync_surface = E_NEW(E_Explicit_Sync_Surface, 1);
+   if (!explicit_sync_surface)
+     {
+        wl_client_post_no_memory(client);
+        goto fail;
+     }
+
+   explicit_sync_surface->acquire_fence_fd = -1;
+   explicit_sync_surface->pending_acquire_fence_fd = -1;
+
+   explicit_sync_surface->resource = wl_resource_create(client,
+                                                        &zwp_linux_surface_synchronization_v1_interface,
+                                                        wl_resource_get_version(resource),
+                                                        id);
+   if (!explicit_sync_surface->resource)
+     {
+        wl_client_post_no_memory(client);
+        goto fail;
+     }
+
+   wl_resource_set_implementation(explicit_sync_surface->resource,
+                                  &_e_explicit_sync_surface_implementation,
+                                  explicit_sync_surface,
+                                  _e_explicit_sync_surface_cb_resource_destroy);
+
+   ec->explicit_sync_surface = explicit_sync_surface;
+   explicit_sync_surface->ec = ec;
+   explicit_sync_surface->ec_delfn = e_object_delfn_add(E_OBJECT(ec),
+                                                        _e_explicit_sync_surface_cb_ec_free,
+                                                        NULL);
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Create", explicit_sync_surface->ec, explicit_sync_surface);
+
+   return;
+
+fail:
+   if (explicit_sync_surface)
+     E_FREE(explicit_sync_surface);
+}
+
+static void
+_e_explicit_sync_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+   wl_resource_destroy(resource);
+}
+
+static const struct zwp_linux_explicit_synchronization_v1_interface e_explicit_sync_implementation = {
+   _e_explicit_sync_cb_destroy,
+   _e_explicit_sync_cb_get_synchronization
+};
+
+static void
+_explicit_sync_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+   struct wl_resource *resource;
+   E_Explicit_Sync *explicit_sync;
+
+   explicit_sync = _explicit_sync;
+
+   resource = wl_resource_create(client, &zwp_linux_explicit_synchronization_v1_interface, version, id);
+   if (!resource)
+     {
+        wl_client_post_no_memory(client);
+        return;
+     }
+
+   wl_resource_set_implementation(resource, &e_explicit_sync_implementation,
+                                  explicit_sync, NULL);
+}
+
+EINTERN Eina_Bool
+e_explicit_sync_surface_commit(E_Explicit_Sync_Surface *explicit_sync_surface)
+{
+   E_Client *ec;
+   E_Comp_Wl_Buffer *buffer;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync_surface, EINA_FALSE);
+
+   ec = explicit_sync_surface->ec;
+   if ((!ec) || e_object_is_del(E_OBJECT(ec)))
+     {
+        ERR("invalid ec");
+        return EINA_FALSE;
+     }
+
+   if (explicit_sync_surface->pending_acquire_fence_fd != -1)
+     {
+        if (explicit_sync_surface->acquire_fence_fd != -1)
+          _e_explicit_sync_fd_clear(&explicit_sync_surface->acquire_fence_fd);
+
+        _e_explicit_sync_fd_move(&explicit_sync_surface->acquire_fence_fd,
+                                 &explicit_sync_surface->pending_acquire_fence_fd);
+     }
+
+   if (explicit_sync_surface->pending_buffer_release)
+     {
+        buffer = _e_explicit_sync_comp_wl_buffer_get(ec);
+        if (buffer)
+          {
+             buffer->buffer_release = explicit_sync_surface->pending_buffer_release;
+             explicit_sync_surface->pending_buffer_release = NULL;
+          }
+        else
+          {
+             /* send error? */
+            //  wl_resource_post_error(explicit_sync_surface->resource,
+                          //                         ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_BUFFER,
+                          //                         "no buffer for synchronization");
+          }
+     }
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Commit", explicit_sync_surface->ec, explicit_sync_surface);
+
+   return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_explicit_sync_surface_sync(E_Explicit_Sync_Surface *explicit_sync_surface)
+{
+   E_Explicit_Sync *explicit_sync;
+   E_Egl_Sync *egl_sync;
+
+   explicit_sync = _explicit_sync;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync, EINA_FALSE);
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync_surface, EINA_FALSE);
+
+   if (explicit_sync_surface->acquire_fence_fd == -1)
+     return EINA_TRUE;
+
+   egl_sync = e_egl_sync_fence_create_with_fd(explicit_sync_surface->acquire_fence_fd);
+   EINA_SAFETY_ON_NULL_GOTO(egl_sync, fail);
+
+   if (!e_egl_sync_wait(egl_sync))
+     {
+        ERR("Failed to wait on E_Egl_Sync");
+        goto fail;
+     }
+
+   e_egl_sync_destroy(egl_sync);
+
+   EX_SYNC_TRACE("Explicit_Sync Surface:%p Sync", explicit_sync_surface->ec, explicit_sync_surface);
+
+   return EINA_TRUE;
+
+fail:
+   if (egl_sync)
+     e_egl_sync_destroy(egl_sync);
+
+   return EINA_FALSE;
+}
+
+EINTERN Eina_Bool
+e_explicit_sync_init(void)
+{
+   E_Explicit_Sync *explicit_sync;
+   tdm_hwc *thwc;
+   E_Output *output;
+   Eina_List *l;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, EINA_FALSE);
+
+   if (_explicit_sync) return EINA_TRUE;
+   if (!e_comp_gl_get()) return EINA_FALSE;
+   if (!e_egl_sync_enabled_get()) return EINA_FALSE;
+
+   EINA_LIST_FOREACH(e_comp->e_comp_screen->outputs, l, output)
+     {
+         if (!output)
+           continue;
+         if (!output->hwc)
+           return EINA_FALSE;
+         if (output->hwc->hwc_policy != E_HWC_POLICY_WINDOWS)
+           return EINA_FALSE;
+         if (!hwc->tdm_hwc_fence)
+           return EINA_FALSE;
+     }
+
+   explicit_sync = E_NEW(E_Explicit_Sync, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(explicit_sync, EINA_FALSE);
+
+   explicit_sync->global = wl_global_create(e_comp_wl->wl.disp,
+                                           &zwp_linux_explicit_synchronization_v1_interface,
+                                           2,
+                                           explicit_sync,
+                                           _explicit_sync_cb_bind);
+   EINA_SAFETY_ON_NULL_GOTO(explicit_sync->global, fail);
+
+   _explicit_sync = explicit_sync;
+   _explicit_sync_enabled = EINA_TRUE;
+
+   return EINA_TRUE;
+
+fail:
+   if (explicit_sync)
+     {
+        if (explicit_sync->global)
+          wl_global_destroy(explicit_sync->global);
+
+        E_FREE(explicit_sync);
+     }
+
+   return EINA_FALSE;
+}
+
+EINTERN void
+e_explicit_sync_deinit(void)
+{
+   E_Explicit_Sync *explicit_sync;
+
+   explicit_sync = _explicit_sync;
+   if (!explicit_sync) return;
+
+   wl_global_destroy(explicit_sync->global);
+   E_FREE(explicit_sync);
+
+   _explicit_sync = NULL;
+}
+
+EINTERN void
+e_explicit_sync_trace_debug(Eina_Bool onoff)
+{
+   if (onoff == ex_sync_trace) return;
+   ex_sync_trace = onoff;
+   INF("Explicit Sync Debug is %s", onoff?"ON":"OFF");
+}
+
+EINTERN Eina_Bool
+e_explicit_sync_enabled_get(void)
+{
+   return _explicit_sync_enabled;
+}
diff --git a/src/bin/e_explicit_sync.h b/src/bin/e_explicit_sync.h
new file mode 100644 (file)
index 0000000..3b71692
--- /dev/null
@@ -0,0 +1,48 @@
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Explicit_Sync E_Explicit_Sync;
+typedef struct _E_Explicit_Sync_Surface E_Explicit_Sync_Surface;
+typedef struct _E_Explicit_Sync_Buffer_Release E_Explicit_Sync_Buffer_Release;
+
+#else
+#ifndef E_EXPLICIT_SYNC_H
+#define E_EXPLICIT_SYNC_H
+
+struct _E_Explicit_Sync
+{
+   struct wl_global *global;
+};
+
+struct _E_Explicit_Sync_Surface
+{
+   struct wl_resource *resource;
+
+   int pending_acquire_fence_fd;
+   int acquire_fence_fd;
+
+   E_Client *ec;
+   E_Object_Delfn *ec_delfn;
+
+   E_Explicit_Sync_Buffer_Release *pending_buffer_release;
+};
+
+struct _E_Explicit_Sync_Buffer_Release
+{
+   struct wl_resource *resource;
+   int fence_fd;
+};
+
+
+EINTERN Eina_Bool e_explicit_sync_init(void);
+EINTERN void      e_explicit_sync_deinit(void);
+EINTERN void      e_explicit_sync_trace_debug(Eina_Bool onoff);
+EINTERN Eina_Bool e_explicit_sync_enabled_get(void);
+
+EINTERN Eina_Bool e_explicit_sync_surface_commit(E_Explicit_Sync_Surface *explicit_sync_surface);
+EINTERN Eina_Bool e_explicit_sync_surface_sync(E_Explicit_Sync_Surface *explicit_sync_surface);
+
+EINTERN Eina_Bool e_explicit_sync_buffer_release_fence_fd_set(E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release, int fence_fd);
+EINTERN void      e_explicit_sync_buffer_release_destroy(E_Explicit_Sync_Buffer_Release *explicit_sync_buffer_release);
+
+#endif // E_EXPLICIT_SYNC_H
+#endif
index 0598a0f6b6c33ccd9b136e7d76bc1d3378d6f57c..34c70433c9c579164d5cda1cfbd3df3dcca639a0 100644 (file)
@@ -356,6 +356,8 @@ e_hwc_new(E_Output *output, Eina_Bool primary_output)
    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, NULL);
    hwc->output = output;
 
+   hwc->commit_fence_fd = -1;
+
    /*
     * E20 has two hwc policy options.
     * 1. One is the E_HWC_POLICY_PLANES.
@@ -398,6 +400,8 @@ e_hwc_new(E_Output *output, Eina_Bool primary_output)
           hwc->tdm_hwc_video_transform = EINA_TRUE;
         if (hwc_caps & TDM_HWC_CAPABILITY_VIDEO_SCANOUT)
           hwc->tdm_hwc_video_scanout = EINA_TRUE;
+        if (hwc_caps & TDM_HWC_CAPABILITY_FENCE)
+          hwc->tdm_hwc_fence = EINA_TRUE;
      }
 
    /* set the pirmary_output */
@@ -444,6 +448,9 @@ e_hwc_del(E_Hwc *hwc)
 
    _e_hwc_ee_deinit(hwc);
 
+   if (hwc->commit_fence_fd >= 0)
+     close(hwc->commit_fence_fd);
+
    E_FREE(hwc);
 }
 
index 1cac472e6a2392d5dd7f2d88ccb35b6aa4ec8224..6716cca31b0cf9e51f0ea80a387058555dafe322 100644 (file)
@@ -140,6 +140,9 @@ struct _E_Hwc
    int                  flapse;
 
    Eina_Bool            present_sync;
+
+   Eina_Bool            tdm_hwc_fence;
+   int                  commit_fence_fd;
 };
 
 E_API extern int E_EVENT_HWC_ACTIVE;
index 7c7f5ea19a75ceb2de92b0d236bb64780e432e20..1fc024281670988760c32c11a04d0e5c0c6a0f74 100644 (file)
@@ -1364,6 +1364,12 @@ e_hwc_window_buffer_fetch(E_Hwc_Window *hwc_window)
    error = tdm_hwc_window_set_buffer(thwc_window, hwc_window->buffer.tsurface);
    EINA_SAFETY_ON_TRUE_RETURN_VAL(error != TDM_ERROR_NONE, EINA_FALSE);
 
+   if (ec && ec->explicit_sync_surface)
+     {
+        error = tdm_hwc_window_set_acquire_fence(thwc_window, ec->explicit_sync_surface->acquire_fence_fd);
+        EINA_SAFETY_ON_TRUE_RETURN_VAL(error != TDM_ERROR_NONE, EINA_FALSE);
+     }
+
    return EINA_TRUE;
 }
 
index 31388395c6828fb4f1b122479f4bb87f5fd09265..5f759fe2c3d3c7703d709762787c16044b569e14 100644 (file)
@@ -71,6 +71,7 @@ struct _E_Hwc_Window_Buffer
    E_Hwc_Window_Queue            *queue;
    struct wl_listener             queue_destroy_listener;
    Eina_Bool                      from_queue;
+   int                            sync_fence_fd;
 };
 
 struct _E_Hwc_Window
@@ -164,7 +165,9 @@ struct _E_Hwc_Window_Target
    Eina_Bool           is_rendering;
    int                 max_transition_failures;
 
-   Eina_Bool skip_surface_set;
+   Eina_Bool           skip_surface_set;
+
+   E_Egl_Sync         *end_render_sync;
 };
 
 struct _E_Hwc_Window_Commit_Data {
index bb955b142b5e31ec1613da08f6b549f6582164b7..71aa53a62fbb89c22de8ff445af3114f95f538a1 100644 (file)
@@ -71,6 +71,7 @@ struct _E_Hwc_Windows_Buffer_Comp_Info
 {
    E_Presentation_Time_Container presentation_container;
    Eina_Bool skip;
+   E_Egl_Sync *release_fence;
 };
 
 static Eina_Bool ehws_trace = EINA_FALSE;
@@ -583,6 +584,13 @@ _e_hwc_windows_target_buffer_fetch(E_Hwc *hwc, Eina_Bool tdm_set)
         if (tdm_set)
           tdm_hwc_set_client_target_buffer(thwc, hwc_window->buffer.tsurface, fb_damage);
 
+        if (target_hwc_window->end_render_sync)
+          {
+             int fence = e_egl_sync_fence_fd_dup(target_hwc_window->end_render_sync);
+             tdm_hwc_set_client_target_acquire_fence(thwc, fence);
+             close(fence);
+          }
+
         if (ehws_trace)
           {
              rendered_windows = _e_hwc_windows_target_window_rendered_windows_get(hwc_window->buffer.tsurface);
@@ -636,6 +644,7 @@ _e_hwc_windows_target_buffer_fetch(E_Hwc *hwc, Eina_Bool tdm_set)
         CLEAR(fb_damage);
 
         tdm_hwc_set_client_target_buffer(thwc, NULL, fb_damage);
+        tdm_hwc_set_client_target_acquire_fence(thwc, -1);
      }
 
    return EINA_TRUE;
@@ -920,6 +929,9 @@ _e_hwc_windows_target_window_surface_queue_trace_cb(tbm_surface_queue_h surface_
                                            EHWS_RENDERED_WINDOWS_KEY,
                                            _e_hwc_windows_rendered_windows_free);
         target_hwc_window->dequeued_tsurface = tsurface;
+        buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(tsurface);
+        if (buffer_comp_info && buffer_comp_info->release_fence)
+           e_egl_sync_wait(buffer_comp_info->release_fence);
 
         if (!eina_list_data_find(target_hwc_window->rendering_tsurfaces, tsurface))
           {
@@ -1061,6 +1073,37 @@ _e_hwc_windows_target_window_queue_set(E_Hwc_Window_Target *target_hwc_window)
    return EINA_TRUE;
 }
 
+static void
+_e_hwc_windows_target_window_render_flush_pre_cb(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   E_Hwc_Window_Target *target_hwc_window = (E_Hwc_Window_Target *)data;
+   E_Hwc_Window *hwc_window;
+   E_Hwc *hwc;
+   Eina_List *l;
+
+   hwc = target_hwc_window->hwc;
+   if (!(e_egl_sync_enabled_get() && e_egl_sync_enabled_get())) return;
+
+   if (target_hwc_window->end_render_sync)
+     {
+        e_egl_sync_destroy(target_hwc_window->end_render_sync);
+        target_hwc_window->end_render_sync = NULL;
+     }
+
+   target_hwc_window->end_render_sync = e_egl_sync_fence_create();
+   if (!target_hwc_window->end_render_sync)
+     EHWSERR("Failed to create E_Egl_Sync", hwc);
+
+   EINA_LIST_FOREACH(hwc->visible_windows, l, hwc_window)
+     {
+        if (!hwc_window->is_deleted) continue;
+        if (!hwc_window->ec) continue;
+        if (!hwc_window->ec->explicit_sync_surface) continue;
+
+        e_explicit_sync_surface_sync(hwc_window->ec->explicit_sync_surface);
+     }
+}
+
 static void
 _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
 {
@@ -1073,6 +1116,7 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
    Eina_List *rendered_windows = NULL;
    Eina_List *visible_windows = NULL;
    Eina_List *l;
+   Eina_Bool fence_enabled;
 
    EHWSTRACE("{%s} gets render_flush_post noti.", NULL, target_hwc_window->hwc, "@TARGET WINDOW@");
 
@@ -1106,6 +1150,8 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
    if (!buffer_comp_info)
      EHWSERR("fail to get buffer_comp_info tsurface:%p", target_hwc_window->hwc, target_hwc_window->dequeued_tsurface);
 
+   fence_enabled = (e_egl_sync_enabled_get() && e_explicit_sync_enabled_get());
+
    /* all ecs have been composited so we can attach a list of composited e_hwc_windows to the surface
     * which contains their ecs composited */
    rendered_windows = eina_list_clone(target_hwc_window->rendered_windows);
@@ -1135,6 +1181,22 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
          */
         if (!buffer->resource) continue;
 
+        if ((fence_enabled) && (buffer->buffer_release) && (target_hwc_window->end_render_sync))
+          {
+             int fence_fd = -1;
+
+             fence_fd = e_egl_sync_fence_fd_dup(target_hwc_window->end_render_sync);
+             if (fence_fd != -1)
+               {
+                  if (!e_explicit_sync_buffer_release_fence_fd_set(buffer->buffer_release, fence_fd))
+                    close(fence_fd);
+
+                  continue;
+               }
+             else
+               EHWSERR("failed to dup native fence fd", target_hwc_window->hwc);
+          }
+
         buffer_ref = E_NEW(E_Comp_Wl_Buffer_Ref, 1);
         if (!buffer_ref) continue;
 
@@ -1164,6 +1226,10 @@ _e_hwc_windows_target_window_free(E_Hwc_Window_Target *target_hwc_window)
                            EVAS_CALLBACK_RENDER_FLUSH_POST,
                            _e_hwc_windows_target_window_render_flush_post_cb);
 
+   evas_event_callback_del(target_hwc_window->evas,
+                           EVAS_CALLBACK_RENDER_FLUSH_PRE,
+                           _e_hwc_windows_target_window_render_flush_pre_cb);
+
    ecore_main_fd_handler_del(target_hwc_window->event_hdlr);
    close(target_hwc_window->event_fd);
 
@@ -1227,6 +1293,11 @@ _e_hwc_windows_target_window_new(E_Hwc *hwc)
                            _e_hwc_windows_target_window_render_flush_post_cb,
                            target_hwc_window);
 
+   evas_event_callback_add(evas,
+                           EVAS_CALLBACK_RENDER_FLUSH_PRE,
+                           _e_hwc_windows_target_window_render_flush_pre_cb,
+                           target_hwc_window);
+
    return target_hwc_window;
 
 fail:
@@ -3285,11 +3356,89 @@ e_hwc_windows_render(E_Hwc *hwc)
    return EINA_TRUE;
 }
 
+static void
+_e_hwc_windows_release_fence_fd_update(E_Hwc *hwc)
+{
+   E_Hwc_Window *hwc_window;
+   E_Hwc_Window_Target *target_hwc_window;
+   E_Hwc_Window_Queue_Buffer *queue_buffer;
+   E_Hwc_Windows_Buffer_Comp_Info *comp_info;
+   tdm_hwc_window **thwc_wins = NULL;
+   int *release_fences = NULL;
+   uint32_t num_thwc_wins = 0;
+   tdm_error ret = TDM_ERROR_NONE;
+   int i;
+
+   target_hwc_window = hwc->target_hwc_window;
+   EINA_SAFETY_ON_NULL_RETURN(target_hwc_window);
+
+   hwc_window = (E_Hwc_Window *)target_hwc_window;
+   if ((hwc_window->display.buffer.tsurface) && (hwc_window->display.buffer.queue))
+     {
+        comp_info = _e_hwc_windows_buffer_comp_info_get(hwc_window->display.buffer.tsurface);
+        EINA_SAFETY_ON_NULL_RETURN(comp_info);
+
+        if (comp_info->release_fence)
+          e_egl_sync_destroy(comp_info->release_fence);
+
+        comp_info->release_fence = e_egl_sync_fence_create_with_fd(hwc->commit_fence_fd);
+
+        queue_buffer = e_hwc_window_queue_buffer_find(hwc_window->display.buffer.queue,
+                                                      hwc_window->display.buffer.tsurface);
+        if (queue_buffer)
+          e_hwc_window_queue_buffer_release(hwc_window->display.buffer.queue, queue_buffer);
+
+        /* prevent release buffer to queue in commit handler */
+        hwc_window->display.buffer.queue = NULL;
+     }
+
+   ret = tdm_hwc_get_release_fences(hwc->thwc, &num_thwc_wins, NULL, NULL);
+   EINA_SAFETY_ON_FALSE_GOTO(ret == TDM_ERROR_NONE, clean);
+
+   if (!num_thwc_wins) return;
+
+   thwc_wins = E_NEW(tdm_hwc_window *, num_thwc_wins);
+   EINA_SAFETY_ON_NULL_GOTO(thwc_wins, clean);
+
+   release_fences = E_NEW(int, num_thwc_wins);
+   EINA_SAFETY_ON_NULL_GOTO(release_fences, clean);
+
+   ret = tdm_hwc_get_release_fences(hwc->thwc, &num_thwc_wins, thwc_wins, release_fences);
+   EINA_SAFETY_ON_FALSE_GOTO(ret == TDM_ERROR_NONE, clean);
+
+   for (i = 0; i < num_thwc_wins; i++)
+     {
+        hwc_window = _e_hwc_windows_window_find_by_twin(hwc, thwc_wins[i]);
+
+        if ((!hwc_window) ||
+            (!hwc_window->display.buffer_ref.buffer) ||
+            (!hwc_window->display.buffer_ref.buffer->buffer_release))
+          {
+             close(release_fences[i]);
+             continue;
+          }
+
+        if (!e_explicit_sync_buffer_release_fence_fd_set(hwc_window->display.buffer_ref.buffer->buffer_release,
+                                                         release_fences[i]))
+          {
+             close(release_fences[i]);
+             continue;
+          }
+
+        e_comp_wl_buffer_reference(&hwc_window->display.buffer_ref, NULL);
+     }
+
+clean:
+  if (thwc_wins) free(thwc_wins);
+  if (release_fences) free(release_fences);
+}
+
 EINTERN Eina_Bool
 e_hwc_windows_commit(E_Hwc *hwc, E_Output_Display_Mode display_mode)
 {
    E_Output *output = NULL;
    tdm_error error = TDM_ERROR_NONE;
+   int commit_fence_fd = -1;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
 
@@ -3376,8 +3525,19 @@ e_hwc_windows_commit(E_Hwc *hwc, E_Output_Display_Mode display_mode)
              goto fail;
           }
 
-          /* send tizen_hwc_commit feedback committed */
-          e_comp_wl_tizen_hwc_committed();
+        error = tdm_hwc_get_commit_fence(hwc->thwc, &commit_fence_fd);
+        if (error != TDM_ERROR_NONE)
+          EHWSERR("tdm_hwc_get_commit_sync_fence_fd failed.", hwc);
+
+        if (hwc->commit_fence_fd >= 0)
+          close(hwc->commit_fence_fd);
+
+        hwc->commit_fence_fd = commit_fence_fd;
+
+        _e_hwc_windows_release_fence_fd_update(hwc);
+
+        /* send tizen_hwc_commit feedback committed */
+        e_comp_wl_tizen_hwc_committed();
      }
 
    return EINA_TRUE;
index 3e4db816566724d97c92038fb7a83aee359389c4..0aa4d3fa4f465d27ea0477c67e9dcd71df7770c2 100644 (file)
@@ -57,6 +57,7 @@
 #include "e_hwc_window.h"
 #include "e_hwc_window_queue.h"
 #include "e_presentation_time.h"
+#include "e_explicit_sync.h"
 #include "e_egl_sync.h"
 #include "e_comp_wl.h"
 #include "e_comp_wl_subsurface.h"
index 3324874f184f2a06ba859431f96e3d785d3d045e..523f43ce690789d5849f83fa4ebb8c9b7f3285d3 100644 (file)
@@ -3369,6 +3369,14 @@ _e_info_client_proc_trace(int argc, char **argv)
                }
              return;
           }
+        else if (eina_streq(argv[2], "exsync"))
+          {
+             if (!_e_info_client_eldbus_message_with_args("trace_message_exsync", NULL, "i", onoff))
+               {
+                  printf("_e_info_client_eldbus_message_with_args error");
+               }
+             return;
+          }
      }
 
 arg_err:
@@ -6165,7 +6173,7 @@ static ProcInfo procs_to_tracelogs[] =
 #endif
    {
       "trace",
-      "[hwc | serial] [off: 0, on: 1]",
+      "[hwc | serial | exsync] [off: 0, on: 1]",
       "Show the trace log in detail",
       _e_info_client_proc_trace
    },
index c986d233a733493c515afec85ae99f97597bb8e3..82ddb359429995dd6147d4f419adae9a178a08c8 100644 (file)
@@ -4872,6 +4872,24 @@ e_info_server_cb_hwc(const Eldbus_Service_Interface *iface EINA_UNUSED, const El
    return reply;
 }
 
+static Eldbus_Message *
+e_info_server_cb_exsync_trace_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
+{
+   Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+   uint32_t on;
+
+   if (!eldbus_message_arguments_get(msg, "i", &on))
+     {
+        ERR("Error getting arguments.");
+        return reply;
+     }
+
+   if (on == 0 || on == 1)
+     e_explicit_sync_trace_debug(on);
+
+   return reply;
+}
+
 static Eldbus_Message *
 e_info_server_cb_show_plane_state(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
 {
@@ -6864,6 +6882,7 @@ static const Eldbus_Method methods[] = {
    { "trace_message_hwc", ELDBUS_ARGS({"i", "trace_message_hwc"}), NULL, e_info_server_cb_hwc_trace_message, 0},
    { "trace_message_serial", ELDBUS_ARGS({"i", "trace_message_serial"}), NULL, e_info_server_cb_serial_trace_message, 0},
    { "trace_message_prstt", ELDBUS_ARGS({"i", "trace_message_presentation_time"}), NULL, e_info_server_cb_prstt_trace_message, 0},
+   { "trace_message_exsync", ELDBUS_ARGS({"i", "trace_message_ex_sync"}), NULL, e_info_server_cb_exsync_trace_message, 0},
    { "hwc", ELDBUS_ARGS({"i", "hwc"}), NULL, e_info_server_cb_hwc, 0},
    { "show_plane_state", NULL, NULL, e_info_server_cb_show_plane_state, 0},
    { "show_pending_commit", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_PENDING_COMMIT")", "array of pending commit"}), e_info_server_cb_show_pending_commit, 0},
index ad8309a19d6fa2d5c40b27a9e89d26f00daf617a..5aca4940057fb258070bf9258c2d8b6046e7173a 100644 (file)
@@ -240,7 +240,9 @@ typedef enum
    "\tenlightenment_info -trace serial 1\n"                          \
    "\tenlightenment_info -trace serial 0\n"                          \
    "\tenlightenment_info -trace prstt 1\n"                           \
-   "\tenlightenment_info -trace prstt 0\n"
+   "\tenlightenment_info -trace prstt 0\n"                           \
+   "\tenlightenment_info -trace exsync 1\n"                           \
+   "\tenlightenment_info -trace exsync 0\n"
 
 /* -------------------------------------------------------------------------- */
 /* HWC WINS                                                                   */