--- /dev/null
+#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)
+{
+ if (fd < 0) return EINA_FALSE;
+
+ 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)
+ {
+ if (buffer->buffer_release)
+ e_explicit_sync_buffer_release_destroy(buffer->buffer_release);
+
+ buffer->buffer_release = explicit_sync_surface->pending_buffer_release;
+ explicit_sync_surface->pending_buffer_release = NULL;
+ }
+ }
+
+ 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 = NULL;
+ E_Output *output;
+ Eina_Bool ret = EINA_FALSE;
+ 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) continue;
+ if (output->hwc->hwc_policy != E_HWC_POLICY_WINDOWS) continue;
+ if (!output->hwc->tdm_hwc_fence) continue;
+
+ ret = EINA_TRUE;
+ }
+
+ if (!ret) 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->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;
+}