ecore_wl2: sync between UI and video 87/235487/9 accepted/tizen/unified/20200624.130233 submit/tizen/20200623.055220
authorShinwoo Kim <cinoo.kim@samsung.com>
Fri, 5 Jun 2020 02:48:59 +0000 (11:48 +0900)
committerShinwoo Kim <cinoo.kim@samsung.com>
Tue, 23 Jun 2020 02:06:09 +0000 (11:06 +0900)
There is a requirement to sync of geometry changes such as move
and resize between UI and video. EFL could not take care of the
video geometry becasue it is handled by separated process.

This patch makes it possible by using a subsurface.
The video process will use the subsurface and surface commits
on this subsurface will be cached and only applied when the
parent surface's state is applied. In this case the parent
surface is working for UI.

*tizen_only

Change-Id: I287cb7bf7858ea5e3efc7f2bd32ce6279896586f

src/lib/ecore_wl2/Ecore_Wl2.h
src/lib/ecore_wl2/ecore_wl2_display.c
src/lib/ecore_wl2/ecore_wl2_private.h
src/lib/ecore_wl2/ecore_wl2_window.c

index 1c6074d..ae02c91 100644 (file)
@@ -2959,6 +2959,103 @@ EAPI Ecore_Wl2_Input *ecore_wl2_window_keyboard_get(Ecore_Wl2_Window *win);
 // TIZEN_ONLY(20171114): support a pointer warp
 EAPI Eina_Bool ecore_wl2_window_pointer_warp(Ecore_Wl2_Window *win, int x, int y);
 //
+// TIZEN_ONLY(20200601): support sync between ui and video
+/*
+ * @typedef Ecore_Wl2_Window_Render_Sync_Type
+ * Type for Ecore_Wl2_Window_Render_Sync_Type to create a file descriptor
+ * which is used for informing render event on the native surface
+ *
+ * @see ecore_wl2_window_render_sync_fd_create
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+typedef enum _Ecore_Wl2_Window_Render_Sync_Type
+{
+   ECORE_WL2_WINDOW_RENDER_SYNC_COMMIT = 0, /**< To get commit event emitted after calling wl_surface_commit */
+   ECORE_WL2_WINDOW_RENDER_SYNC_PRESENT = 1 /**< To get presentation event emitted after the compositor draws */
+} Ecore_Wl2_Window_Render_Sync_Type;
+
+/**
+ * @brief Create a video surface for a given window
+ *
+ * @param win The window to create a video surface
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI Eina_Bool ecore_wl2_window_video_surface_create(Ecore_Wl2_Window *win);
+
+/**
+ * @brief Get video surface for a given window
+ *
+ * @param win The window to get video surface
+ * @return The wl_surface which is used by this window as a video surface
+ *         It provided as void type
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI void *ecore_wl2_window_video_surface_get(Ecore_Wl2_Window *win);
+
+/**
+ * @brief Destroy a video surface for a given window
+ *
+ * @param win The window to destroy a video surface
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI Eina_Bool ecore_wl2_window_video_surface_destroy(Ecore_Wl2_Window *win);
+
+/**
+ * @brief Set video surface for a given window to synchronized mode
+ *        the default commit behaviour is desynchronized mode.
+ *
+ * @param win The window to set video surface to synchronized mode
+ * @param sync EINA_TRUE to set video surface to synchronized mode,
+ *             EINA_FALSE to set video surface to desynchronized mode
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI Eina_Bool ecore_wl2_window_video_surface_sync_set(Ecore_Wl2_Window *win, Eina_Bool sync);
+
+/**
+ * @brief Set destination area of video surface for a given window
+ *
+ * @param win The window 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_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI Eina_Bool ecore_wl2_window_video_surface_destination_set(Ecore_Wl2_Window *win, int x, int y, int w, int h);
+
+
+/**
+ * @brief Create a file descriptor for rendering sync for a given window
+ *
+ * @param win The window to create a file descriptor for rendering sync
+ * @param sync_type The Ecore_Wl2_Window_Render_Sync_Type to create a file descriptor
+ *             ECORE_WL2_WINDOW_RENDER_SYNC_COMMIT to get commit event,
+ *             ECORE_WL2_WINDOW_RENDER_SYNC_PRESENT to get presentation event
+ * @return The file descriptor. It must be closed manually  by the caller using `close`
+ *
+ * @see Ecore_Wl2_Window_Group
+ *
+ * @ingroup Ecore_Wl2_Window_Group
+ * @since_tizen 6.0
+ */
+EAPI int ecore_wl2_window_render_sync_fd_create(Ecore_Wl2_Window *win, Ecore_Wl2_Window_Render_Sync_Type sync_type);
+//
 
 //TIZEN_ONLY(20171108): add a new API to ecore_wl2_sync
 /** @internal */
index 5c2d338..a7e2e36 100644 (file)
@@ -1030,6 +1030,7 @@ _ecore_wl2_display_globals_cleanup(Ecore_Wl2_Display *ewd)
    if (ewd->wl.tz_clipboard) tizen_clipboard_destroy(ewd->wl.tz_clipboard);
    if (ewd->wl.tz_screen_rotation) tizen_screen_rotation_destroy(ewd->wl.tz_screen_rotation);
    if (ewd->wl.tz_moveresize) tizen_move_resize_destroy(ewd->wl.tz_moveresize);
+   if (ewd->wl.tz_video) tizen_video_destroy(ewd->wl.tz_video);
 //
 
    if (ewd->wl.registry) wl_registry_destroy(ewd->wl.registry);
index bdb2c66..87071ae 100644 (file)
@@ -135,6 +135,9 @@ struct _Ecore_Wl2_Display
         // TIZEN_ONLY(20190430): support client appinfo
         struct tizen_launch_appinfo *tz_appinfo;
         //
+        // TIZEN_ONLY(20200601): support sync between ui and video
+        struct tizen_video *tz_video;
+        //
 
         int compositor_version;
      } wl;
@@ -396,6 +399,16 @@ struct _Ecore_Wl2_Window
    // TIZEN_ONLY(20190807): Support for wl_egl interface
    Ecore_Wl2_Egl_Window *egl_win;
    //
+
+   // TIZEN_ONLY(20200601): support sync between ui and video
+   struct
+     {
+        struct wl_surface *surface;
+        struct wl_subsurface *subsurface;
+        struct tizen_viewport *viewport;
+        Eina_Bool sync : 1;
+     } video;
+   //
 };
 
 struct _Ecore_Wl2_Output
index d522977..c81c4f5 100644 (file)
@@ -5,6 +5,10 @@
 #include "ecore_wl2_private.h"
 #include "efl-hints-client-protocol.h"
 
+// TIZEN_ONLY(20200601): support sync between ui and video
+#include <wayland-tbm-client.h>
+//
+
 //TIZEN_ONLY(20171216): add ecore_wl2_window_find
 /* local variables */
 static Eina_Hash *_windows = NULL;
@@ -1322,6 +1326,12 @@ ecore_wl2_window_free(Ecore_Wl2_Window *window)
    window->tz_resource = NULL;
    //
 
+   // TIZEN_ONLY(20200601): support sync between ui and video
+   if (window->video.viewport) tizen_viewport_destroy(window->video.viewport);
+   if (window->video.subsurface) wl_subsurface_destroy(window->video.subsurface);
+   if (window->video.surface) wl_surface_destroy(window->video.surface);
+   //
+
    if (window->callback) wl_callback_destroy(window->callback);
    window->callback = NULL;
 
@@ -3466,6 +3476,225 @@ ecore_wl2_window_pointer_warp(Ecore_Wl2_Window *win, int x, int y)
 }
 //
 
+// TIZEN_ONLY(20200601): support sync between ui and video
+/* The video surface created in ecore_wl2 is used for informing the video area.
+   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. */
+void
+buffer_fill_zero(tbm_surface_h surface)
+{
+   tbm_surface_info_s info;
+   int *img;
+   unsigned int height, stride;
+   unsigned int i, j;
+
+   tbm_surface_map(surface, TBM_OPTION_WRITE, &info);
+
+   img = (int *)info.planes[0].ptr;
+   height = tbm_surface_get_height(surface);
+   stride = info.planes[0].stride;
+
+   memset(img, 0x0, sizeof(int) * stride * height);
+
+   tbm_surface_unmap(surface);
+}
+
+
+EAPI Eina_Bool
+ecore_wl2_window_video_surface_create(Ecore_Wl2_Window *win)
+{
+   Ecore_Wl2_Display *display;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
+   if (win->video.surface) return EINA_TRUE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->display, EINA_FALSE);
+   display = win->display;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(display->wl.compositor, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(display->wl.subcompositor, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(display->wl.tz_policy, EINA_FALSE);
+
+   win->video.surface = wl_compositor_create_surface(display->wl.compositor);
+
+   if (!win->video.surface)
+     {
+        ERR("Failed to create video surface");
+        return EINA_FALSE;
+     }
+
+   win->video.subsurface =
+     wl_subcompositor_get_subsurface(display->wl.subcompositor,
+                                     win->video.surface, win->surface);
+
+   if (!win->video.subsurface)
+     {
+        ERR("Failed to create video subsurface");
+        wl_surface_destroy(win->video.surface);
+        win->video.surface = NULL;
+        return EINA_FALSE;
+     }
+
+   tizen_policy_place_subsurface_below_parent(display->wl.tz_policy, win->video.subsurface);
+
+   struct wayland_tbm_client *tbm_client;
+   tbm_surface_h surface;
+   struct wl_buffer *wl_buffer;
+
+   tbm_client = wayland_tbm_client_init(display->wl.display);
+   surface = tbm_surface_create(2, 2, TBM_FORMAT_ARGB8888);
+   wl_buffer = wayland_tbm_client_create_buffer(tbm_client, surface);
+   buffer_fill_zero(surface);
+
+   /* need to attach surface */
+   wl_surface_attach(win->video.surface, wl_buffer, 0, 0);
+   wl_surface_commit(win->video.surface);
+
+   return EINA_TRUE;
+}
+
+EAPI void *
+ecore_wl2_window_video_surface_get(Ecore_Wl2_Window *win)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win, NULL);
+   return win->video.surface;
+}
+
+EAPI Eina_Bool
+ecore_wl2_window_video_surface_destroy(Ecore_Wl2_Window *win)
+{
+   Ecore_Wl2_Display *display;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->display, EINA_FALSE);
+
+   display = win->display;
+
+   if (display->wl.tz_video)
+     {
+        tizen_video_destroy(display->wl.tz_video);
+        display->wl.tz_video = NULL;
+     }
+
+   if (win->video.viewport)
+     {
+        tizen_viewport_destroy(win->video.viewport);
+        win->video.viewport = NULL;
+     }
+
+   if (win->video.subsurface)
+     {
+        wl_subsurface_destroy(win->video.subsurface);
+        win->video.subsurface = NULL;
+     }
+
+   if (win->video.surface)
+     {
+        wl_surface_destroy(win->video.surface);
+        win->video.surface = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl2_window_video_surface_sync_set(Ecore_Wl2_Window *win, Eina_Bool sync)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->video.subsurface, EINA_FALSE);
+
+   sync = !!sync;
+   if (win->video.sync == sync) return EINA_TRUE;
+
+   win->video.sync = sync;
+
+   if (sync)
+     wl_subsurface_set_sync(win->video.subsurface);
+   else
+     wl_subsurface_set_desync(win->video.subsurface);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl2_window_video_surface_destination_set(Ecore_Wl2_Window *win, 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(win, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->display, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->video.surface, EINA_FALSE);
+
+   display = win->display;
+
+   if (!win->video.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;
+          }
+
+        win->video.viewport = tizen_video_get_viewport(display->wl.tz_video, win->video.surface);
+     }
+
+   if (!win->video.viewport)
+     {
+        ERR("Failed to get video viewport");
+        return EINA_FALSE;
+     }
+
+   tizen_viewport_set_destination(win->video.viewport, x, y, w, h);
+   wl_surface_commit(win->video.surface);
+
+   return EINA_TRUE;
+}
+
+EAPI int
+ecore_wl2_window_render_sync_fd_create(Ecore_Wl2_Window *win, Ecore_Wl2_Window_Render_Sync_Type sync_type)
+{
+   int sync_fd = -1;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win, sync_fd);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(win->egl_win, sync_fd);
+
+   switch (sync_type)
+     {
+      case ECORE_WL2_WINDOW_RENDER_SYNC_COMMIT:
+        sync_fd = wl_egl_window_tizen_create_commit_sync_fd(win->egl_win->native_win);
+        break;
+      case ECORE_WL2_WINDOW_RENDER_SYNC_PRESENT:
+        sync_fd = wl_egl_window_tizen_create_presentation_sync_fd(win->egl_win->native_win);
+        break;
+      default:
+        break;
+     }
+
+   return sync_fd;
+}
+//
 
 //TIZEN_ONLY: ecore_wl2: add ecore_wl_window_video_has
 EAPI void