ecore_wl2: expose subsurface interface 44/246044/8 submit/tizen/20201108.215920
authorShinwoo Kim <cinoo.kim@samsung.com>
Thu, 22 Oct 2020 11:41:30 +0000 (20:41 +0900)
committerShinwoo Kim <cinoo.kim@samsung.com>
Fri, 6 Nov 2020 04:28:54 +0000 (04:28 +0000)
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
src/lib/ecore_wl2/ecore_wl2_internal.h
src/lib/ecore_wl2/ecore_wl2_private.h
src/lib/ecore_wl2/ecore_wl2_subsurf.c
src/lib/ecore_wl2/ecore_wl2_window.c

index cd7eeec..4eaa3d0 100644 (file)
@@ -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
 
index d0af8bb..009f9ab 100644 (file)
@@ -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.
index 39b16b2..e9da70e 100644 (file)
@@ -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
index 5409fd2..a4d0162 100644 (file)
@@ -4,6 +4,34 @@
 
 #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)
 {
@@ -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);
+}
+//
index 7c99855..b9212ec 100644 (file)
@@ -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;