e_hwc_window: Synchronize frame in case of surface and subsurface are transformed 14/257714/9
authorChangyeon Lee <cyeon.lee@samsung.com>
Thu, 6 May 2021 11:29:12 +0000 (20:29 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Fri, 11 Jun 2021 03:30:35 +0000 (03:30 +0000)
e_hwc_window_present_sync api for synchronizing hwc with gl compositing
if e_hwc_client_present_sync api is called,
tbm_surface and tdm_hwc_window_info of hwc_window will be updated
after gl compositing is done.

update data is dequeued when buffer for gl compositing is dequeued
andthen it is enqueued when buffer for gl compositing is acquired.

Change-Id: I076a92d63379b084eeeceffd6666a4f7bfa44157

src/bin/e_hwc_window.c
src/bin/e_hwc_window.h
src/bin/e_hwc_windows.c

index bf58fc0..0061443 100644 (file)
@@ -821,6 +821,79 @@ _e_hwc_window_client_cb_del(void *data EINA_UNUSED, E_Client *ec)
    e_hwc_window_client_type_override(ec->hwc_window);
 }
 
+static void
+_e_hwc_window_client_subsurface_present_sync(E_Client *ec)
+{
+   E_Hwc_Window_State state;
+   Eina_List *l;
+   E_Client *subc;
+
+   if (!ec->hwc_window) return;
+
+   state = e_hwc_window_accepted_state_get(ec->hwc_window);
+   if ((state == E_HWC_WINDOW_STATE_DEVICE) || (state == E_HWC_WINDOW_STATE_VIDEO))
+     e_hwc_window_present_sync(ec->hwc_window);
+
+   EINA_LIST_FOREACH(ec->comp_data->sub.below_list_pending, l, subc)
+     {
+        if (!subc->hwc_window) continue;
+        _e_hwc_window_client_subsurface_present_sync(subc);
+     }
+
+   EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
+     {
+        if (!subc->hwc_window) continue;
+        _e_hwc_window_client_subsurface_present_sync(subc);
+     }
+}
+
+static void
+_e_hwc_window_client_cb_transform_change(void *data EINA_UNUSED, E_Client *ec)
+{
+   E_Output *output;
+   E_Zone *zone;
+   E_Client *topmost;
+   Eina_List *l;
+   E_Client *subc;
+   E_Hwc_Window_State state;
+
+   EINA_SAFETY_ON_NULL_RETURN(ec);
+
+   zone = ec->zone;
+   EINA_SAFETY_ON_NULL_RETURN(zone);
+   EINA_SAFETY_ON_NULL_RETURN(zone->output_id);
+
+   output = e_output_find(zone->output_id);
+   EINA_SAFETY_ON_NULL_RETURN(output);
+
+   /* If an e_client belongs to the e_output managed by hwc_plane policy,
+    * there's no need to deal with hwc_windows. */
+   if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) return;
+   if (!ec->hwc_window) return;
+
+   if (!e_comp_wl_video_subsurface_has(ec) && !e_comp_wl_normal_subsurface_has(ec))
+     return;
+
+   topmost = e_comp_wl_topmost_parent_get(ec);
+   if (topmost != ec) return;
+
+   /* if window is device state, sync is not needed */
+   state = e_hwc_window_accepted_state_get(ec->hwc_window);
+   if (state != E_HWC_WINDOW_STATE_CLIENT) return;
+
+   EINA_LIST_FOREACH(ec->comp_data->sub.below_list_pending, l, subc)
+     {
+        if (!subc->hwc_window) continue;
+        _e_hwc_window_client_subsurface_present_sync(subc);
+     }
+
+   EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
+     {
+        if (!subc->hwc_window) continue;
+        _e_hwc_window_client_subsurface_present_sync(subc);
+     }
+}
+
 static Eina_Bool
 _e_hwc_window_client_cb_zone_set(void *data, int type, void *event)
 {
@@ -875,6 +948,8 @@ e_hwc_window_init(void)
 {
    E_LIST_HOOK_APPEND(hwc_window_client_hooks, E_CLIENT_HOOK_DEL,
                       _e_hwc_window_client_cb_del, NULL);
+   E_LIST_HOOK_APPEND(hwc_window_client_hooks, E_CLIENT_HOOK_TRANSFORM_CHANGE,
+                      _e_hwc_window_client_cb_transform_change, NULL);
    E_LIST_HANDLER_APPEND(hwc_window_event_hdlrs, E_EVENT_CLIENT_ZONE_SET,
                          _e_hwc_window_client_cb_zone_set, NULL);
 
@@ -1285,6 +1360,9 @@ e_hwc_window_info_update(E_Hwc_Window *hwc_window)
 
         if (e_object_is_del(E_OBJECT(ec))) return EINA_FALSE;
 
+        if ((hwc_window->present_sync) || (eina_list_count(hwc_window->pending_update_list)))
+          return EINA_FALSE;
+
         if (e_hwc_window_is_cursor(hwc_window))
           {
              if (!_e_hwc_window_cursor_info_get(hwc_window, &hwc_win_info))
@@ -1438,6 +1516,9 @@ e_hwc_window_buffer_fetch(E_Hwc_Window *hwc_window)
         return EINA_TRUE;
      }
 
+   if ((hwc_window->present_sync) || (eina_list_count(hwc_window->pending_update_list)))
+     return EINA_FALSE;
+
    ec = hwc_window->ec;
 
    if ((hwc_window->is_deleted) || (!ec) || e_object_is_del(E_OBJECT(ec)))
@@ -2632,6 +2713,8 @@ e_hwc_window_pending_update_data_dequeue(E_Hwc_Window *hwc_window)
             update->info.dst_pos.x, update->info.dst_pos.y,
             update->info.transform);
 
+   hwc_window->pending_update_list = eina_list_append(hwc_window->pending_update_list, update);
+
    return update;
 }
 
@@ -2712,6 +2795,43 @@ e_hwc_window_pending_update_data_has(E_Hwc_Window *hwc_window)
    return EINA_FALSE;
 }
 
+EINTERN Eina_Bool
+e_hwc_window_present_sync(E_Hwc_Window *hwc_window)
+{
+   E_Hwc_Window_Target *target_hwc_window;
+   E_Hwc_Window_State state;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window->hwc, EINA_FALSE);
+
+   target_hwc_window = hwc_window->hwc->target_hwc_window;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE);
+
+   if (e_hwc_window_is_cursor(hwc_window))
+     {
+        EHWERR("cursor doesn't support present sync", hwc_window->ec, hwc_window->hwc, hwc_window);
+        return EINA_FALSE;
+     }
+
+   /* if gl compositor is disabled, present sync isn't needed */
+   state = e_hwc_window_accepted_state_get((E_Hwc_Window *)target_hwc_window);
+   if (state == E_HWC_WINDOW_STATE_NONE)
+      return EINA_TRUE;
+
+   if (hwc_window->present_sync) return EINA_TRUE;
+
+   hwc_window->present_sync = EINA_TRUE;
+
+   if (!eina_list_data_find(target_hwc_window->present_sync_windows, hwc_window))
+     {
+        target_hwc_window->present_sync_windows = eina_list_append(target_hwc_window->present_sync_windows,
+                                                                   hwc_window);
+        e_hwc_window_ref(hwc_window);
+     }
+
+   return EINA_TRUE;
+}
+
 EINTERN E_Hwc_Window_Hook *
 e_hwc_window_hook_add(E_Hwc_Window_Hook_Point hookpoint, E_Hwc_Window_Hook_Cb func, const void *data)
 {
index 93a7343..cf3911f 100644 (file)
@@ -153,6 +153,8 @@ struct _E_Hwc_Window
    Eina_Bool                      obscured_by_target;
 
    E_Presentation_Time_Container  presentation_container;
+
+   Eina_Bool                      present_sync;
 };
 
 struct _E_Hwc_Window_Target
@@ -176,6 +178,8 @@ struct _E_Hwc_Window_Target
    struct wl_listener  pp_queue_destroy_listener;
 
    E_Egl_Sync         *end_render_sync;
+
+   Eina_List          *present_sync_windows;
 };
 
 struct _E_Hwc_Window_Commit_Data {
@@ -247,6 +251,8 @@ EINTERN void                    e_hwc_window_presentation_time_feedback_present(
 EINTERN void                    e_hwc_window_presentation_time_feedback_discard(E_Hwc_Window *hwc_window);
 EINTERN void                    e_hwc_window_presentation_time_feedback_take(E_Hwc_Window *hwc_window, E_Presentation_Time_Container *container);
 
+EINTERN Eina_Bool               e_hwc_window_present_sync(E_Hwc_Window *hwc_window);
+
 EINTERN E_Hwc_Window_Update_Data *e_hwc_window_pending_update_data_dequeue(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool                 e_hwc_window_pending_update_data_enqueue(E_Hwc_Window *hwc_window, E_Hwc_Window_Update_Data *update);
 EINTERN Eina_Bool                 e_hwc_window_pending_update_data_dequeue_cancel(E_Hwc_Window *hwc_window, E_Hwc_Window_Update_Data *update);
index 23abf22..7512cdf 100644 (file)
@@ -63,6 +63,7 @@ struct _E_Hwc_Windows_Buffer_Comp_Info
    E_Presentation_Time_Container presentation_container;
    Eina_Bool skip;
    E_Egl_Sync *release_fence;
+   Eina_List *pending_update_list;
 };
 
 static Eina_Bool ehws_trace = EINA_FALSE;
@@ -1058,6 +1059,84 @@ _e_hwc_windows_rendered_windows_free(void *data)
     }
 }
 
+static Eina_Bool
+_e_hwc_windows_pending_update_data_enqueue(E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info)
+{
+   E_Hwc_Window_Update_Data *update;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(buffer_comp_info, EINA_FALSE);
+
+   EINA_LIST_FREE(buffer_comp_info->pending_update_list, update)
+     e_hwc_window_pending_update_data_enqueue(update->hwc_window, update);
+
+   buffer_comp_info->pending_update_list = NULL;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_hwc_windows_pending_update_data_dequeue(E_Hwc_Window_Target *target_hwc_window,
+                                           E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info)
+{
+   Eina_List *pending_update_list = NULL;
+   E_Hwc_Window_Update_Data *update;
+   E_Hwc_Window *hwc_window;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(buffer_comp_info, EINA_FALSE);
+
+   EINA_LIST_FREE(target_hwc_window->present_sync_windows, hwc_window)
+     {
+        hwc_window->present_sync = EINA_FALSE;
+
+        update = e_hwc_window_pending_update_data_dequeue(hwc_window);
+        if (update)
+          {
+             pending_update_list = eina_list_append(pending_update_list, update);
+             if (e_hwc_window_is_video(hwc_window))
+               e_client_video_commit_data_release(hwc_window->ec, 0, 0, 0);
+          }
+
+        e_object_unref(E_OBJECT(hwc_window));
+     }
+
+   EINA_LIST_FREE(buffer_comp_info->pending_update_list, update)
+     e_hwc_window_pending_update_data_enqueue(update->hwc_window, update);
+
+   buffer_comp_info->pending_update_list = pending_update_list;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_hwc_windows_pending_update_data_clear(E_Hwc_Window_Target *target_hwc_window)
+{
+   E_Hwc_Window *hwc_window;
+   E_Hwc_Window_Update_Data *update;
+   tbm_surface_h tsurface;
+   E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info;
+   Eina_List *l, *ll;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE);
+
+   EINA_LIST_FREE(target_hwc_window->present_sync_windows, hwc_window)
+     {
+        hwc_window->present_sync = EINA_FALSE;
+        e_object_unref(E_OBJECT(hwc_window));
+     }
+
+   EINA_LIST_FOREACH_SAFE(target_hwc_window->rendering_tsurfaces, l, ll, tsurface)
+     {
+        buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(tsurface);
+        if (!buffer_comp_info) continue;
+
+        EINA_LIST_FREE(buffer_comp_info->pending_update_list, update)
+          e_hwc_window_pending_update_data_dequeue_cancel(update->hwc_window, update);
+     }
+
+   return EINA_TRUE;
+}
+
 /* gets called as somebody modifies target_window's queue */
 static void
 _e_hwc_windows_target_window_surface_queue_trace_cb(tbm_surface_queue_h surface_queue,
@@ -1102,6 +1181,10 @@ _e_hwc_windows_target_window_surface_queue_trace_cb(tbm_surface_queue_h surface_
 
         target_hwc_window->rendering_tsurfaces =
           eina_list_remove(target_hwc_window->rendering_tsurfaces, tsurface);
+
+        buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(tsurface);
+        if (buffer_comp_info)
+          _e_hwc_windows_pending_update_data_enqueue(buffer_comp_info);
      }
 
    /* tsurface has been released at the queue */
@@ -1333,6 +1416,8 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
      {
         EHWSINF("flush_post_cb is called but tsurface isn't dequeued", NULL, target_hwc_window->hwc);
 
+        _e_hwc_windows_pending_update_data_clear(target_hwc_window);
+
         if (eina_list_count(target_hwc_window->rendered_windows))
           {
              EINA_LIST_FREE(target_hwc_window->rendered_windows, hwc_window)
@@ -1356,7 +1441,9 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
      }
 
    buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(target_hwc_window->dequeued_tsurface);
-   if (!buffer_comp_info)
+   if (buffer_comp_info)
+     _e_hwc_windows_pending_update_data_dequeue(target_hwc_window, buffer_comp_info);
+   else
      EHWSERR("fail to get buffer_comp_info tsurface:%p", target_hwc_window->hwc, target_hwc_window->dequeued_tsurface);
 
    fence_enabled = e_hwc_windows_fence_enabled_get(target_hwc_window->hwc);
@@ -2398,7 +2485,6 @@ _e_hwc_windows_changes_update(E_Hwc *hwc)
    E_Hwc_Window *hwc_window = NULL;
    Eina_Bool update_changes = EINA_FALSE;
    const Eina_List *l;
-   Eina_Bool ret = EINA_FALSE;
 
    if (hwc->property_changed)
      {
@@ -2414,29 +2500,22 @@ _e_hwc_windows_changes_update(E_Hwc *hwc)
    if (_e_hwc_windows_device_state_available_update(hwc))
      update_changes = EINA_TRUE;
 
-   /* fetch the target buffer (try acquire) */
-   if (_e_hwc_windows_target_buffer_fetch(hwc))
-     update_changes = EINA_TRUE;
-
    EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
      {
         if (e_hwc_window_is_target(hwc_window)) continue;
         if (e_hwc_window_is_external(hwc_window)) continue;
 
         /* fetch the window buffer */
-        ret = e_hwc_window_buffer_fetch(hwc_window);
-        if (ret)
+        if (e_hwc_window_buffer_fetch(hwc_window))
           update_changes = EINA_TRUE;
         else
           {
              /* sometimes client add frame cb without buffer attach */
              if ((hwc_window->ec) &&
+                 (hwc_window->ec->pixmap) &&
+                 (e_pixmap_type_get(hwc_window->ec->pixmap) == E_PIXMAP_TYPE_WL) &&
                  (hwc_window->accepted_state == E_HWC_WINDOW_STATE_DEVICE))
-               {
-                  if ((hwc_window->ec->pixmap) &&
-                      (e_pixmap_type_get(hwc_window->ec->pixmap) == E_PIXMAP_TYPE_WL))
-                    e_pixmap_image_clear(hwc_window->ec->pixmap, 1);
-               }
+               e_pixmap_image_clear(hwc_window->ec->pixmap, 1);
           }
 
         /* update the window's info */
@@ -2451,6 +2530,10 @@ _e_hwc_windows_changes_update(E_Hwc *hwc)
           update_changes = EINA_TRUE;
      }
 
+   /* fetch the target buffer (try acquire) */
+   if (_e_hwc_windows_target_buffer_fetch(hwc))
+     update_changes = EINA_TRUE;
+
    if (hwc->pp_set)
      _e_hwc_windows_pp_hwc_window_update(hwc);
 
@@ -2469,6 +2552,9 @@ _e_hwc_windows_target_state_set(E_Hwc_Window_Target *target_hwc_window, E_Hwc_Wi
 {
    E_Hwc_Window *target_window = (E_Hwc_Window *)target_hwc_window;
 
+   if ((state == E_HWC_WINDOW_STATE_NONE) && (e_hwc_window_state_get(target_window) != state))
+     _e_hwc_windows_pending_update_data_clear(target_hwc_window);
+
    e_hwc_window_state_set(target_window, state, EINA_FALSE);
    e_hwc_window_accepted_state_set(target_window, state);
 }