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
* @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
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
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
* @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.
* @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
* @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.
{
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;
};
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
Eina_Hash *_ecore_wl2_window_hash_get(void);
//
+// TIZEN_ONLY(20201022): support restack video
+Eina_Bool buffer_fill_zero(tbm_surface_h surface);
+//
+
#endif
#include "ecore_wl2_private.h"
+// TIZEN_ONLY(20201022): support restack video
+#include <wayland-tbm-client.h>
+
+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)
{
{
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;
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);
+}
+//
}
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;
}
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);
// 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);
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)
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)
{
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;