From 72eddff4f3cee10669425b9b997c493ee4a71020 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Thu, 22 Oct 2020 20:41:30 +0900 Subject: [PATCH] ecore_wl2: expose subsurface interface There is a requirement to change subsurface z-order. The Player should set display using subsurface instead of window to show more than two video surfaces. - ecore_wl2_subsurface_new - ecore_wl2_subsurface_del - ecore_wl2_subsurface_sync_set - ecore_wl2_subsurface_native_surface_get - ecore_wl2_subsurface_place_surface_above - ecore_wl2_subsurface_place_surface_below - ecore_wl2_subsurface_video_surface_prepare - ecore_wl2_subsurface_video_surface_destination_set Change-Id: Iba9633bad700a621642d0c874c05e24ed0e84d45 --- src/lib/ecore_wl2/Ecore_Wl2.h | 144 ++++++++++++++++++++++ src/lib/ecore_wl2/ecore_wl2_internal.h | 32 ++--- src/lib/ecore_wl2/ecore_wl2_private.h | 19 ++- src/lib/ecore_wl2/ecore_wl2_subsurf.c | 218 +++++++++++++++++++++++++++++++++ src/lib/ecore_wl2/ecore_wl2_window.c | 37 +++--- 5 files changed, 416 insertions(+), 34 deletions(-) diff --git a/src/lib/ecore_wl2/Ecore_Wl2.h b/src/lib/ecore_wl2/Ecore_Wl2.h index cd7eeec..4eaa3d0 100644 --- a/src/lib/ecore_wl2/Ecore_Wl2.h +++ b/src/lib/ecore_wl2/Ecore_Wl2.h @@ -45,6 +45,7 @@ extern "C" { * @li @ref Ecore_Wl2_Display_Group * @li @ref Ecore_Wl2_Window_Group * @li @ref Ecore_Wl2_Input_Group + * @li @ref Ecore_Wl2_Subsurface_Group */ # ifndef _ECORE_WL2_WINDOW_PREDEF @@ -3064,6 +3065,149 @@ EAPI int ecore_wl2_window_render_sync_fd_create(Ecore_Wl2_Window *win, Ecore_Wl2 EAPI void ecore_wl2_sync(void); // +// TIZEN_ONLY(20201022): support restack video +/** + * @defgroup Ecore_Wl2_Subsurface_Group Functions to manipulate subsurfaces. + * @ingroup Ecore_Wl2_Group + * + * Functions to manipulate wayland subsurfaces, using Ecore_Wl2_Subsurface. + * + * This API is intended to expose Wayland subsurface functionality, although it + * should not be necessary for most applications to use it, as soon as we have + * means to make Evas automatically switch Evas images to use subsurfaces. + * + * It can/should be used, for instance, when subsurfaces are needed to be not + * in sync with the main window surface. + */ + +/** + * @brief Create and return a new subsurface. + * + * Create a new surface (and subsurface interface), with the parent surface + * being the one associated with the given window. + * + * @param window The window. It must be visible, otherwise there will be no surface created + * for it yet. + * + * @return the allocated and initialized Ecore_Wl2_Subsurface object, or + * NULL on failure + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since 1.17 + * @since_tizen 6.0 + */ +EAPI Ecore_Wl2_Subsurface * ecore_wl2_subsurface_new(Ecore_Wl2_Window *window); + +/** + * @brief Destroy the given subsurface, as well as the surface associated with it. + * + * @param subsurface the subsurface + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since 1.17 + * @since_tizen 6.0 + */ +EAPI void ecore_wl2_subsurface_del(Ecore_Wl2_Subsurface *subsurface); + +/** + * @brief Enables or disables sub-surface synchronization + * + * When synchronization is enabled, surface commits on the subsurface + * will be cached and only applied when the parent surface's state is + * applied. This ensures atomic updates of the parent and all of its + * synchronized sub-surfaces. + * + * When synchronization is disabled, commits will apply to the pending + * state directly without caching, just like a normal wl_surface. If + * there are already cached events when this is set, those events are + * applied simultaneously with the desync event. + * + * Attempting to enable synchronization when the subsurface already + * thinks it's sync'd, or desync when it believes its desync'd, will + * be trivially ignored and will not generate a Wayland event. + * + * See Wayland's set_desync documentation for further details and + * exceptional cases. + * + * @param subsurface the subsurface + * @param sync true to enable synchronization, false to desynchronize + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since 1.17 + * @since_tizen 6.0 + */ +EAPI void ecore_wl2_subsurface_sync_set(Ecore_Wl2_Subsurface *subsurface, Eina_Bool sync); + +/** + * @brief Get the wl_surface for this subsurface + * + * @param subsurface the subsurface + * + * @return the wl_surface associated with this subsurface, or NULL on failure, + * provided as void type + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since_tizen 6.0 + */ +EAPI void *ecore_wl2_subsurface_native_surface_get(Ecore_Wl2_Subsurface *subsurface); + +/** + * @brief Place subsurface on layer above a reference subsurface + * + * Moves the subsurface to just above the reference subsurface, + * changing the z-order. The reference subsurface must + * be either a sibling or parent surface, else a protocol error will + * be generated. + * + * @param subsurface the subsurface + * @param other the sibling reference subsurface, or NULL for parent surface + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since_tizen 6.0 + */ +EAPI void ecore_wl2_subsurface_place_surface_above(Ecore_Wl2_Subsurface *subsurface, Ecore_Wl2_Subsurface *other); + +/** + * @brief Place subsurface on layer below a reference subsurface + * + * See ecore_wl2_subsurface_place_surface_above. + * + * @param subsurface the subsurface + * @param other the sibling reference subsurface, or NULL for parent surface + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since_tizen 6.0 + */ +EAPI void ecore_wl2_subsurface_place_surface_below(Ecore_Wl2_Subsurface *subsurface, Ecore_Wl2_Subsurface *other); + +/** + * @brief Prepare video surface for a given subsurface + * + * @param subsurface The subsurface to prepare video surface + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since_tizen 6.0 + */ +EAPI Eina_Bool ecore_wl2_subsurface_video_surface_prepare(Ecore_Wl2_Subsurface *subsurface); + +/** + * @brief Set destination area of video surface for a given subsurface + * + * @param subsurface The subsurface to set destination area of video surface + * @param x X position of destination area + * @param y Y position of destination area + * @param w Width of destination area + * @param h Height of destination area + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise + * + * @ingroup Ecore_Wl2_Subsurface_Group + * @since_tizen 6.0 + */ +EAPI Eina_Bool ecore_wl2_subsurface_video_surface_destination_set(Ecore_Wl2_Subsurface *subsurface, int x, int y, int w, int h); +// # undef EAPI # define EAPI diff --git a/src/lib/ecore_wl2/ecore_wl2_internal.h b/src/lib/ecore_wl2/ecore_wl2_internal.h index d0af8bb..009f9ab 100644 --- a/src/lib/ecore_wl2/ecore_wl2_internal.h +++ b/src/lib/ecore_wl2/ecore_wl2_internal.h @@ -203,20 +203,6 @@ EAPI Eina_Bool ecore_wl2_offer_supports_mime(Ecore_Wl2_Offer *offer, const char EAPI void ecore_wl2_offer_finish(Ecore_Wl2_Offer *offer); /** - * @defgroup Ecore_Wl2_Subsurface_Group Functions to manipulate subsurfaces. - * @ingroup Ecore_Wl2_Group - * - * Functions to manipulate wayland subsurfaces, using Ecore_Wl2_Subsurface. - * - * This API is intended to expose Wayland subsurface functionality, although it - * should not be necessary for most applications to use it, as soon as we have - * means to make Evas automatically switch Evas images to use subsurfaces. - * - * It can/should be used, for instance, when subsurfaces are needed to be not - * in sync with the main window surface. - */ - -/** * Create and return a new subsurface. * * Create a new surface (and subsurface interface), with the parent surface @@ -231,7 +217,13 @@ EAPI void ecore_wl2_offer_finish(Ecore_Wl2_Offer *offer); * @ingroup Ecore_Wl2_Subsurface_Group * @since 1.17 */ +// TIZEN_ONLY(20201022): support restack video +/* This API moved to Ecore_Wl2.h +// EAPI Ecore_Wl2_Subsurface *ecore_wl2_subsurface_new(Ecore_Wl2_Window *window); +// TIZEN_ONLY(20201022): support restack video +*/ +// /** * Destroy the given subsurface, as well as the surface associated with it. @@ -241,7 +233,13 @@ EAPI Ecore_Wl2_Subsurface *ecore_wl2_subsurface_new(Ecore_Wl2_Window *window); * @ingroup Ecore_Wl2_Subsurface_Group * @since 1.17 */ +// TIZEN_ONLY(20201022): support restack video +/* This API moved to Ecore_Wl2.h +// EAPI void ecore_wl2_subsurface_del(Ecore_Wl2_Subsurface *subsurface); +// TIZEN_ONLY(20201022): support restack video +*/ +// /** * Get the wl_surface for this subsurface @@ -337,7 +335,13 @@ EAPI void ecore_wl2_subsurface_place_below(Ecore_Wl2_Subsurface *subsurface, str * @ingroup Ecore_Wl2_Subsurface_Group * @since 1.17 */ + // TIZEN_ONLY(20201022): support restack video + /* This API moved to Ecore_Wl2.h + // EAPI void ecore_wl2_subsurface_sync_set(Ecore_Wl2_Subsurface *subsurface, Eina_Bool sync); +// TIZEN_ONLY(20201022): support restack video +*/ +// /** * Set an opaque region for the given subsurface. diff --git a/src/lib/ecore_wl2/ecore_wl2_private.h b/src/lib/ecore_wl2/ecore_wl2_private.h index 39b16b2..e9da70e 100644 --- a/src/lib/ecore_wl2/ecore_wl2_private.h +++ b/src/lib/ecore_wl2/ecore_wl2_private.h @@ -189,8 +189,18 @@ struct _Ecore_Wl2_Subsurface { struct wl_surface *surface; struct wl_subsurface *subsurface; + + // TIZEN_ONLY(20201022): support restack video + struct tizen_viewport *viewport; + tbm_surface_h tbm_surface; + struct wl_buffer *wl_buffer; + // } wl; + // TIZEN_ONLY(20201022): support restack video + Eina_Bool video : 1; + // + Eina_Bool sync : 1; }; @@ -409,11 +419,14 @@ struct _Ecore_Wl2_Window struct wl_surface *surface; struct wl_subsurface *subsurface; struct tizen_viewport *viewport; - struct wayland_tbm_client *tbm_client; tbm_surface_h tbm_surface; struct wl_buffer *wl_buffer; Eina_Bool sync : 1; } video; + + /* no need to be a member of video struct, + because no need to init more than one */ + struct wayland_tbm_client *tbm_client; // // TIZEN_ONLY(20200601): support tizen_renderer_surface @@ -898,4 +911,8 @@ void _ecore_wl2_window_shutdown(void); Eina_Hash *_ecore_wl2_window_hash_get(void); // +// TIZEN_ONLY(20201022): support restack video +Eina_Bool buffer_fill_zero(tbm_surface_h surface); +// + #endif diff --git a/src/lib/ecore_wl2/ecore_wl2_subsurf.c b/src/lib/ecore_wl2/ecore_wl2_subsurf.c index 5409fd2..a4d0162 100644 --- a/src/lib/ecore_wl2/ecore_wl2_subsurf.c +++ b/src/lib/ecore_wl2/ecore_wl2_subsurf.c @@ -4,6 +4,34 @@ #include "ecore_wl2_private.h" +// TIZEN_ONLY(20201022): support restack video +#include + +void +_ecore_wl2_subsurface_video_surface_del(Ecore_Wl2_Subsurface *subsurf) +{ + EINA_SAFETY_ON_NULL_RETURN(subsurf); + + if (subsurf->wl.viewport) + { + tizen_viewport_destroy(subsurf->wl.viewport); + subsurf->wl.viewport = NULL; + } + + if (subsurf->wl.wl_buffer) + { + wayland_tbm_client_destroy_buffer(subsurf->parent->tbm_client, subsurf->wl.wl_buffer); + subsurf->wl.wl_buffer = NULL; + } + + if (subsurf->wl.tbm_surface) + { + tbm_surface_destroy(subsurf->wl.tbm_surface); + subsurf->wl.tbm_surface = NULL; + } +} +// + void _ecore_wl2_subsurf_unmap(Ecore_Wl2_Subsurface *subsurf) { @@ -18,6 +46,11 @@ _ecore_wl2_subsurf_free(Ecore_Wl2_Subsurface *subsurf) { Ecore_Wl2_Window *parent; + // TIZEN_ONLY(20201022): support restack video + if (subsurf->video) + _ecore_wl2_subsurface_video_surface_del(subsurf); + // + _ecore_wl2_subsurf_unmap(subsurf); parent = subsurf->parent; @@ -186,3 +219,188 @@ ecore_wl2_subsurface_opaque_region_set(Ecore_Wl2_Subsurface *subsurface, int x, else wl_surface_set_opaque_region(subsurface->wl.surface, NULL); } + + +// TIZEN_ONLY(20201022): support restack video +EAPI Eina_Bool +ecore_wl2_subsurface_video_surface_prepare(Ecore_Wl2_Subsurface *subsurface) +{ + Ecore_Wl2_Window *win; + Ecore_Wl2_Display *display; + + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface->parent, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface->parent->display, EINA_FALSE); + + subsurface->video = EINA_TRUE; + win = subsurface->parent; + display = win->display; + + tizen_policy_place_subsurface_below_parent(display->wl.tz_policy, + subsurface->wl.subsurface); + + if (!win->tbm_client) + { + win->tbm_client = wayland_tbm_client_init(display->wl.display); + if (!win->tbm_client) + { + ERR("Failed to init wayland tbm client"); + goto client_init_err; + } + } + + subsurface->wl.tbm_surface = tbm_surface_create(1, 1, TBM_FORMAT_ARGB8888); + if (!subsurface->wl.tbm_surface) + { + ERR("Failed to create tbm surface"); + goto client_init_err; + } + + subsurface->wl.wl_buffer = wayland_tbm_client_create_buffer(win->tbm_client, + subsurface->wl.tbm_surface); + if (!subsurface->wl.wl_buffer) + { + ERR("Failed to create buffer of tbm client"); + goto create_buf_err; + } + + if (!buffer_fill_zero(subsurface->wl.tbm_surface)) + { + ERR("Failed to fill buffer to zero"); + goto buf_fill_err; + } + + /* need to attach surface */ + wl_surface_attach(subsurface->wl.surface, subsurface->wl.wl_buffer, 0, 0); + wl_surface_commit(subsurface->wl.surface); + + return EINA_TRUE; + +buf_fill_err: + wayland_tbm_client_destroy_buffer(win->tbm_client, subsurface->wl.wl_buffer); + subsurface->wl.wl_buffer = NULL; + +create_buf_err: + tbm_surface_destroy(subsurface->wl.tbm_surface); + subsurface->wl.tbm_surface = NULL; + +client_init_err: + _ecore_wl2_subsurf_free(subsurface); + + return EINA_FALSE; +} + +EAPI void * +ecore_wl2_subsurface_native_surface_get(Ecore_Wl2_Subsurface *subsurface) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface, NULL); + return subsurface->wl.surface; +} + +EAPI Eina_Bool +ecore_wl2_subsurface_video_surface_destination_set(Ecore_Wl2_Subsurface *subsurface, int x, int y, int w, int h) +{ + Ecore_Wl2_Display *display; + struct wl_registry *registry; + Eina_Iterator *globals; + Ecore_Wl2_Global *global; + + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface, EINA_FALSE); + + if (!subsurface->video) + { + ERR("prepare subsurface(%p) first", subsurface); + return EINA_FALSE; + } + + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface->parent, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(subsurface->parent->display, EINA_FALSE); + + display = subsurface->parent->display; + + if (!subsurface->wl.viewport) + { + if (!display->wl.tz_video) + { + registry = ecore_wl2_display_registry_get(display); + if (!registry) return EINA_FALSE; + + globals = ecore_wl2_display_globals_get(display); + if (!globals) return EINA_FALSE; + + EINA_ITERATOR_FOREACH(globals, global) + { + if (strcmp(global->interface, "tizen_video") == 0) + { + display->wl.tz_video = wl_registry_bind(registry, global->id, &tizen_video_interface, 1); + break; + } + } + } + + if (!display->wl.tz_video) + { + ERR("Failed to bind tizen video interface"); + return EINA_FALSE; + } + + subsurface->wl.viewport = tizen_video_get_viewport(display->wl.tz_video, + subsurface->wl.surface); + if (!subsurface->wl.viewport) + { + ERR("Failed to get video viewport"); + return EINA_FALSE; + } + } + + tizen_viewport_set_destination(subsurface->wl.viewport, x, y, w, h); + wl_surface_commit(subsurface->wl.surface); + + return EINA_TRUE; +} + +void +_ecore_wl2_subsurfae_place_surface_stack(Ecore_Wl2_Subsurface *subsurf, Ecore_Wl2_Subsurface *other, Eina_Bool above) +{ + struct wl_surface *psurface; + + EINA_SAFETY_ON_NULL_RETURN(subsurf); + + /* every subsurface is created by window base now, + someday we could use another subsurface as a parent */ + if (other) + { + if (subsurf->parent != other->parent) + { + ERR("Check parent of subsurf(%p) and other(%p)", subsurf, other); + return; + } + if (above) + wl_subsurface_place_above(subsurf->wl.subsurface, other->wl.surface); + else + wl_subsurface_place_below(subsurf->wl.subsurface, other->wl.surface); + } + else + { + psurface = ecore_wl2_window_surface_get(subsurf->parent); + if (above) + wl_subsurface_place_above(subsurf->wl.subsurface, psurface); + else + wl_subsurface_place_below(subsurf->wl.subsurface, psurface); + } +} + +EAPI void +ecore_wl2_subsurface_place_surface_above(Ecore_Wl2_Subsurface *subsurface, Ecore_Wl2_Subsurface *other) +{ + EINA_SAFETY_ON_NULL_RETURN(subsurface); + _ecore_wl2_subsurfae_place_surface_stack(subsurface, other, EINA_TRUE); +} + +EAPI void +ecore_wl2_subsurface_place_surface_below(Ecore_Wl2_Subsurface *subsurface, Ecore_Wl2_Subsurface *other) +{ + EINA_SAFETY_ON_NULL_RETURN(subsurface); + _ecore_wl2_subsurfae_place_surface_stack(subsurface, other, EINA_FALSE); +} +// diff --git a/src/lib/ecore_wl2/ecore_wl2_window.c b/src/lib/ecore_wl2/ecore_wl2_window.c index 7c99855..b9212ec 100644 --- a/src/lib/ecore_wl2/ecore_wl2_window.c +++ b/src/lib/ecore_wl2/ecore_wl2_window.c @@ -1336,7 +1336,7 @@ _ecore_wl2_window_video_surface_destroy(Ecore_Wl2_Window *win) } if (win->video.wl_buffer) { - wayland_tbm_client_destroy_buffer(win->video.tbm_client, win->video.wl_buffer); + wayland_tbm_client_destroy_buffer(win->tbm_client, win->video.wl_buffer); win->video.wl_buffer = NULL; } @@ -1346,11 +1346,6 @@ _ecore_wl2_window_video_surface_destroy(Ecore_Wl2_Window *win) win->video.tbm_surface = NULL; } - if (win->video.tbm_client) - { - wayland_tbm_client_deinit(win->video.tbm_client); - win->video.tbm_client = NULL; - } if (win->video.subsurface) { wl_subsurface_destroy(win->video.subsurface); @@ -1408,6 +1403,12 @@ ecore_wl2_window_free(Ecore_Wl2_Window *window) // TIZEN_ONLY(20200601): support sync between ui and video _ecore_wl2_window_video_surface_destroy(window); + + if (window->tbm_client) + { + wayland_tbm_client_deinit(window->tbm_client); + window->tbm_client = NULL; + } // if (window->callback) wl_callback_destroy(window->callback); @@ -3559,13 +3560,12 @@ ecore_wl2_window_pointer_warp(Ecore_Wl2_Window *win, int x, int y) And there is another video surface created on the player side. The player video surface is filled with video data, and the garbage data of ecore_wl2 video surface can interfere with video data. So fill it with zero here. */ -static Eina_Bool +Eina_Bool buffer_fill_zero(tbm_surface_h surface) { tbm_surface_info_s info; int *img, ret; unsigned int height, stride; - unsigned int i, j; ret = tbm_surface_map(surface, TBM_OPTION_WRITE, &info); if (ret != TBM_SURFACE_ERROR_NONE) @@ -3618,21 +3618,24 @@ ecore_wl2_window_video_surface_create(Ecore_Wl2_Window *win) tizen_policy_place_subsurface_below_parent(display->wl.tz_policy, win->video.subsurface); - win->video.tbm_client = wayland_tbm_client_init(display->wl.display); - if (!win->video.tbm_client) + if (!win->tbm_client) { - ERR("Failed to init wayland tbm client"); - goto client_init_err; + win->tbm_client = wayland_tbm_client_init(display->wl.display); + if (!win->tbm_client) + { + ERR("Failed to init wayland tbm client"); + goto client_init_err; + } } win->video.tbm_surface = tbm_surface_create(1, 1, TBM_FORMAT_ARGB8888); if (!win->video.tbm_surface) { ERR("Failed to create tbm surface"); - goto surf_create_err; + goto client_init_err; } - win->video.wl_buffer = wayland_tbm_client_create_buffer(win->video.tbm_client, + win->video.wl_buffer = wayland_tbm_client_create_buffer(win->tbm_client, win->video.tbm_surface); if (!win->video.wl_buffer) { @@ -3656,17 +3659,13 @@ ecore_wl2_window_video_surface_create(Ecore_Wl2_Window *win) return EINA_TRUE; buf_fill_err: - wayland_tbm_client_destroy_buffer(win->video.tbm_client, win->video.wl_buffer); + wayland_tbm_client_destroy_buffer(win->tbm_client, win->video.wl_buffer); win->video.wl_buffer = NULL; create_buf_err: tbm_surface_destroy(win->video.tbm_surface); win->video.tbm_surface = NULL; -surf_create_err: - wayland_tbm_client_deinit(win->video.tbm_client); - win->video.tbm_client = NULL; - client_init_err: wl_subsurface_destroy(win->video.subsurface); win->video.subsurface = NULL; -- 2.7.4