From: Changyeon Lee Date: Wed, 1 Jul 2020 10:31:51 +0000 (+0900) Subject: add e_explicit_sync for supporting zwp_linux_explicit_synchronization X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fsandbox%2Fcyeon%2Fdevel;p=platform%2Fupstream%2Fenlightenment.git add e_explicit_sync for supporting zwp_linux_explicit_synchronization Change-Id: Ie79f995c41572bf2652f94df9c87013df659a100 --- diff --git a/configure.ac b/configure.ac index 235db3e745..7d69f8bc49 100755 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/packaging/enlightenment.spec b/packaging/enlightenment.spec index e79a82eef5..c936a7bb95 100644 --- a/packaging/enlightenment.spec +++ b/packaging/enlightenment.spec @@ -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 diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 8c826de236..5c7e09cff7 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -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) diff --git a/src/bin/e_client.h b/src/bin/e_client.h index c683a04770..d19e089dc8 100644 --- a/src/bin/e_client.h +++ b/src/bin/e_client.h @@ -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 diff --git a/src/bin/e_comp_screen.c b/src/bin/e_comp_screen.c index cc857b5246..2dbf3fa142 100644 --- a/src/bin/e_comp_screen.c +++ b/src/bin/e_comp_screen.c @@ -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); diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c index 48653e50a5..1537d05077 100644 --- a/src/bin/e_comp_wl.c +++ b/src/bin/e_comp_wl.c @@ -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; diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index c0d21439ad..ac95bd0140 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -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 index 0000000000..916b78a601 --- /dev/null +++ b/src/bin/e_explicit_sync.c @@ -0,0 +1,550 @@ +#include "e.h" +#include +#include + +#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 index 0000000000..3b71692d52 --- /dev/null +++ b/src/bin/e_explicit_sync.h @@ -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 diff --git a/src/bin/e_hwc.c b/src/bin/e_hwc.c index 0598a0f6b6..34c70433c9 100644 --- a/src/bin/e_hwc.c +++ b/src/bin/e_hwc.c @@ -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); } diff --git a/src/bin/e_hwc.h b/src/bin/e_hwc.h index 1cac472e6a..6716cca31b 100644 --- a/src/bin/e_hwc.h +++ b/src/bin/e_hwc.h @@ -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; diff --git a/src/bin/e_hwc_window.c b/src/bin/e_hwc_window.c index 7c7f5ea19a..1fc0242816 100644 --- a/src/bin/e_hwc_window.c +++ b/src/bin/e_hwc_window.c @@ -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; } diff --git a/src/bin/e_hwc_window.h b/src/bin/e_hwc_window.h index 31388395c6..5f759fe2c3 100644 --- a/src/bin/e_hwc_window.h +++ b/src/bin/e_hwc_window.h @@ -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 { diff --git a/src/bin/e_hwc_windows.c b/src/bin/e_hwc_windows.c index bb955b142b..71aa53a62f 100644 --- a/src/bin/e_hwc_windows.c +++ b/src/bin/e_hwc_windows.c @@ -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; diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index 3e4db81656..0aa4d3fa4f 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -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" diff --git a/src/bin/e_info_client.c b/src/bin/e_info_client.c index 3324874f18..523f43ce69 100644 --- a/src/bin/e_info_client.c +++ b/src/bin/e_info_client.c @@ -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 }, diff --git a/src/bin/e_info_server.c b/src/bin/e_info_server.c index c986d233a7..82ddb35942 100644 --- a/src/bin/e_info_server.c +++ b/src/bin/e_info_server.c @@ -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}, diff --git a/src/bin/e_info_shared_types.h b/src/bin/e_info_shared_types.h index ad8309a19d..5aca494005 100644 --- a/src/bin/e_info_shared_types.h +++ b/src/bin/e_info_shared_types.h @@ -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 */