video: Using fallback rendering path in case rendering using hwc has been failed. 64/222464/4 accepted/tizen/unified/20200116.101915 submit/tizen/20200116.021659
authorSeunghun Lee <shiin.lee@samsung.com>
Fri, 10 Jan 2020 08:05:36 +0000 (17:05 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Thu, 16 Jan 2020 02:09:24 +0000 (02:09 +0000)
This patch is intended to remove codes which copied contents of buffer in a
sowftware way in the HWC implementation when trying to create a buffer for pp
as a source buffer.
Because Copying buffer in a software way caused poor frame rate.

Change-Id: I7f0783545a885594c1a6d6a35c77e45f389afa9f

src/bin/video/e_client_video.c
src/bin/video/e_video_internal.h
src/bin/video/iface/e_video_fallback.c
src/bin/video/iface/e_video_hwc.c
src/bin/video/iface/e_video_hwc.h

index 11adb20500792768c03e97ecf0aac7e90ca563f9..67c003b8558b2653021ffa63520238e8378ef650 100644 (file)
@@ -39,6 +39,42 @@ _e_client_video_comp_iface_deinit(E_Client_Video *ecv)
    ecv->iface = NULL;
 }
 
+static Eina_Bool
+_e_client_video_cb_hwc_render_fail(E_Client_Video *ecv)
+{
+   E_Video_Comp_Iface *new_iface;
+   E_Comp_Wl_Buffer *buffer;
+
+   VIN("Callback Called HWC Render Fail: Try to create fallback interface",
+       ecv->ec);
+
+   new_iface = e_video_fallback_iface_create(ecv);
+   if (!new_iface)
+     {
+        VER("Failed to create fallback interface", ecv->ec);
+        /* It does maintain HWC interface since creating fallback interface has
+         * been failed. */
+        return EINA_FALSE;
+     }
+
+   /* workaround:
+    * For redrawing compositor's canvas for video buffer. */
+   buffer = e_pixmap_resource_get(ecv->ec->pixmap);
+   if (buffer)
+     {
+        buffer->type = E_COMP_WL_BUFFER_TYPE_TBM;
+        e_comp_wl_surface_commit(ecv->ec);
+     }
+
+   /* NOTE:
+    * Existing instance 'E_Video_Comp_Iface' for HWC will be freed by HWC
+    * implementation once here it returns EINA_TRUE.
+    * So, just set new interface and DO NOT destroy existing iface here. */
+   ecv->iface = new_iface;
+
+   return EINA_TRUE;
+}
+
 static Eina_Bool
 _e_client_video_comp_iface_init(E_Client_Video *ecv, E_Client *ec)
 {
@@ -63,6 +99,8 @@ _e_client_video_comp_iface_init(E_Client_Video *ecv, E_Client *ec)
      {
         VIN("Initialize the interface of the client_video for HWC mode", ec);
         iface = e_video_hwc_iface_create(ecv);
+        if (iface)
+          e_video_hwc_render_fail_callback_set(iface, _e_client_video_cb_hwc_render_fail);
      }
 
 end:
index 34ae748bc00634585c339c6781740fa61f1a31f7..bc7f743320298f3a5cbb4b79f80db9af0aa676f7 100644 (file)
 typedef struct _E_Client_Video E_Client_Video;
 typedef struct _E_Video_Comp_Iface E_Video_Comp_Iface;
 
+/* A callback which is called when HWC backend fails to render buffer.
+ * HWC iface will destroy its instance by itself if callee returns TRUE. */
+typedef Eina_Bool (*E_Video_Hwc_Render_Fail_Cb)(E_Client_Video *ecv);
+
 struct _E_Video_Comp_Iface
 {
    void            (*destroy)(E_Video_Comp_Iface *iface);
@@ -62,4 +66,7 @@ EINTERN void                 e_client_video_hw_composition_set(E_Client_Video *e
 EINTERN void                 e_client_video_hw_composition_unset(E_Client_Video *ecv);
 EINTERN Eina_Bool            e_client_video_property_allow_get(E_Client_Video *ecv);
 
+/* A set of functions for HWC */
+EINTERN void                 e_video_hwc_render_fail_callback_set(E_Video_Comp_Iface *iface, E_Video_Hwc_Render_Fail_Cb func);
+
 #endif
index ad35ba9f127ed098c245f29f7a25be37ff7bb401..cbc2f997e7e84d83d63687cf8dc4ac1c68e2e621 100644 (file)
@@ -41,7 +41,7 @@ e_video_fallback_iface_create(E_Client_Video *ecv)
 {
    E_Video_Fallback *evs;
 
-   INF("Intializing SW Compositing mode");
+   VIN("Intializing SW Compositing mode", e_client_video_ec_get(ecv));
 
    evs = E_NEW(E_Video_Fallback, 1);
    if (!evs)
index dbe1d2e24ca681a1bd4757fbaa3ddaf5c52e895e..93fdcce9cfe1096867ae273f5769b8fc6a525d4c 100644 (file)
    E_Video_Hwc *evh;                                    \
    evh = container_of(iface, E_Video_Hwc, iface)
 
-static void _e_video_hwc_render(E_Video_Hwc *evh, const char *func);
+static Eina_Bool _e_video_hwc_render(E_Video_Hwc *evh, const char *func);
 static void _e_video_hwc_buffer_show(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform);
 static void _e_video_hwc_buffer_commit(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf);
+static void _e_video_hwc_del(E_Video_Hwc *evh);
 
 static void
 _coord_move_to_axis(int x_axis, int y_axis, int *ox, int *oy)
@@ -129,32 +130,6 @@ _e_video_hwc_vbuf_find_with_comp_buffer(Eina_List *list, E_Comp_Wl_Buffer *comp_
    return NULL;
 }
 
-static E_Comp_Wl_Video_Buf *
-_e_video_hwc_buffer_copy(E_Comp_Wl_Video_Buf *vbuf, int aligned_width, Eina_Bool scanout)
-{
-   E_Comp_Wl_Video_Buf *temp = NULL;
-
-   temp = e_comp_wl_video_buffer_alloc(aligned_width, vbuf->height, vbuf->tbmfmt, scanout);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(temp, NULL);
-
-   temp->comp_buffer = vbuf->comp_buffer;
-
-   VDB("copy vbuf(%d,%dx%d) => vbuf(%d,%dx%d)", NULL,
-       MSTAMP(vbuf), vbuf->width_from_pitch, vbuf->height,
-       MSTAMP(temp), temp->width_from_pitch, temp->height);
-
-   e_comp_wl_video_buffer_copy(vbuf, temp);
-
-#ifdef DUMP_BUFFER
-   char file[256];
-   static int i;
-   snprintf(file, sizeof file, "/tmp/dump/%s_%d.png", "cpy", i++);
-   tdm_helper_dump_buffer(temp->tbm_surface, file);
-#endif
-
-   return temp;
-}
-
 static Eina_Bool
 _e_video_hwc_video_buffer_scanout_check(E_Comp_Wl_Video_Buf *vbuf)
 {
@@ -363,9 +338,8 @@ err:
 static E_Comp_Wl_Video_Buf *
 _e_video_hwc_pp_input_buffer_get(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer)
 {
-   E_Comp_Wl_Video_Buf *vbuf, *temp;
+   E_Comp_Wl_Video_Buf *vbuf;
    Eina_Bool input_buffer_scanout;
-   int aligned_width;
 
    vbuf = _e_video_hwc_vbuf_find_with_comp_buffer(evh->input_buffer_list, comp_buffer);
    if (vbuf)
@@ -379,22 +353,16 @@ _e_video_hwc_pp_input_buffer_get(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer
      }
 
    input_buffer_scanout = _e_video_hwc_video_buffer_scanout_check(vbuf);
+
    if (((evh->pp->align != -1) && (vbuf->width_from_pitch % evh->pp->align != 0)) ||
        ((evh->pp->scanout) && (!input_buffer_scanout)))
      {
-        if ((evh->pp->align != -1) && (vbuf->width_from_pitch % evh->pp->align != 0))
-          aligned_width = ROUNDUP(vbuf->width_from_pitch, evh->pp->align);
-        else
-          aligned_width = vbuf->width;
-
-        temp = _e_video_hwc_buffer_copy(vbuf, aligned_width,
-                                        (input_buffer_scanout || evh->pp->scanout));
+        VER("cannot use this input buffer as an source buffer for pp: "
+            "pp align(%d) bwidth(%d) pp scanout(%d) bscanout(%d)", evh->ec,
+            evh->pp->align, vbuf->width_from_pitch, evh->pp->scanout,
+            input_buffer_scanout);
         e_comp_wl_video_buffer_unref(vbuf);
-
-        if (!temp)
-          return NULL;
-
-        vbuf = temp;
+        return NULL;
      }
 
    DBG("Buffer(%p) created, refcnt:%d scanout:%d",
@@ -1092,8 +1060,12 @@ _e_video_hwc_render_job(void *data)
    E_Video_Hwc *evh;
    E_Client *topmost;
    Eina_Bool render = EINA_FALSE;
+   Eina_Bool render_fail = EINA_FALSE;
+   Eina_Bool res;
 
    evh = data;
+   evh->render.job = NULL;
+
    if (evh->render.map)
      {
         evh->render.map = EINA_FALSE;
@@ -1112,10 +1084,18 @@ _e_video_hwc_render_job(void *data)
    if ((render) || (evh->render.redraw))
      {
         evh->render.redraw = EINA_FALSE;
-        _e_video_hwc_render(evh, __FUNCTION__);
+        render_fail = !_e_video_hwc_render(evh, __FUNCTION__);
      }
 
-   evh->render.job = NULL;
+   if ((render_fail) && (evh->render_fail_cb))
+     {
+        res = evh->render_fail_cb(evh->ecv);
+        if (res)
+          {
+             VIN("Delete HWC interface", evh->ec);
+             _e_video_hwc_del(evh);
+          }
+     }
 }
 
 static void
@@ -1447,35 +1427,35 @@ _e_video_hwc_client_parent_viewable_get(E_Client *ec)
    return EINA_TRUE;
 }
 
-static void
+static Eina_Bool
 _e_video_hwc_render(E_Video_Hwc *evh, const char *func)
 {
    E_Comp_Wl_Buffer *comp_buffer;
    E_Comp_Wl_Video_Buf *input_buffer = NULL;
    E_Client *topmost;
 
-   EINA_SAFETY_ON_NULL_RETURN(evh->ec);
+   EINA_SAFETY_ON_NULL_GOTO(evh->ec, done);
 
    /* buffer can be NULL when camera/video's mode changed. Do nothing and
     * keep previous frame in this case.
     */
    if (!evh->ec->pixmap)
-     return;
+     goto done;
 
    if (!_e_video_hwc_client_visible_get(evh->ec))
      {
         evh->need_force_render = EINA_TRUE;
         _e_video_hwc_hide(evh);
-        return;
+        goto done;
      }
 
    comp_buffer = e_pixmap_resource_get(evh->ec->pixmap);
-   if (!comp_buffer) return;
+   if (!comp_buffer) goto done;
 
    evh->tbmfmt = _e_video_hwc_comp_buffer_tbm_format_get(comp_buffer);
 
    topmost = e_comp_wl_topmost_parent_get(evh->ec);
-   EINA_SAFETY_ON_NULL_RETURN(topmost);
+   EINA_SAFETY_ON_NULL_GOTO(topmost, done);
 
    if(e_comp_wl_viewport_is_changed(topmost))
      {
@@ -1490,7 +1470,7 @@ _e_video_hwc_render(E_Video_Hwc *evh, const char *func)
              VIN("need force render", evh->ec);
              evh->need_force_render = EINA_TRUE;
           }
-        return;
+        goto done;
      }
 
    DBG("====================================== (%s)", func);
@@ -1503,7 +1483,7 @@ _e_video_hwc_render(E_Video_Hwc *evh, const char *func)
         /* Try sending 'wl_surface.frame' in case client
          * submitted same 'wl_buffer' */
         e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
-        return;
+        goto done;
      }
 
    evh->need_force_render = EINA_FALSE;
@@ -1515,20 +1495,29 @@ _e_video_hwc_render(E_Video_Hwc *evh, const char *func)
         /* 1. non converting case */
         input_buffer = _e_video_hwc_input_buffer_get(evh, comp_buffer);
         if (!input_buffer)
-          return;
+          goto done;
 
         _e_video_hwc_buffer_show(evh, input_buffer, evh->geo.tdm.transform);
      }
    else
      {
         if (!_e_video_hwc_pp_render(evh, comp_buffer))
-          return;
+          {
+             VER("Failed to PP render", evh->ec);
+             e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
+             goto render_fail;
+          }
      }
 
    evh->old_geo = evh->geo;
    evh->old_comp_buffer = comp_buffer;
 
    DBG("======================================.");
+
+done:
+   return EINA_TRUE;
+render_fail:
+   return EINA_FALSE;
 }
 
 static E_Client *
@@ -1689,13 +1678,11 @@ _e_video_hwc_client_event_deinit(E_Video_Hwc *evh)
 }
 
 static void
-_e_video_hwc_iface_destroy(E_Video_Comp_Iface *iface)
+_e_video_hwc_del(E_Video_Hwc *evh)
 {
    E_Comp_Wl_Video_Buf *vbuf;
    Eina_List *l = NULL, *ll = NULL;
 
-   IFACE_ENTRY;
-
    _e_video_hwc_hide(evh);
 
    EINA_LIST_FOREACH_SAFE(evh->input_buffer_list, l, ll, vbuf)
@@ -1728,6 +1715,14 @@ _e_video_hwc_iface_destroy(E_Video_Comp_Iface *iface)
    evh->backend.destroy(evh);
 }
 
+static void
+_e_video_hwc_iface_destroy(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   _e_video_hwc_del(evh);
+}
+
 static Eina_Bool
 _e_video_hwc_iface_property_get(E_Video_Comp_Iface *iface, unsigned int id, tdm_value *value)
 {
@@ -1939,3 +1934,27 @@ e_video_hwc_client_mask_update(E_Video_Hwc *evh)
           }
      }
 }
+
+/* Sets render fail callback
+ *
+ * @in iface A instance of this composition mode
+ * @in func The function which will be called.
+ *
+ * This function will be called if rendering is failed.
+ * Once this callback funtion has been called, callee will try to replace its
+ * composition interface to another one. And then callee will return TRUE if
+ * the interface is changed successfully.
+ *
+ * @note For this reason described above, it has to free all of resources if
+ * it gets TRUE as a return value. */
+EINTERN void
+e_video_hwc_render_fail_callback_set(E_Video_Comp_Iface *iface, E_Video_Hwc_Render_Fail_Cb func)
+{
+   E_Video_Hwc *evh;
+
+   evh = container_of(iface, E_Video_Hwc, iface);
+   if (!evh)
+     return;
+
+   evh->render_fail_cb = func;
+}
index e414207a699a82d15cd8c561319dbeb3a169ab57..16f0f164ae833d9ad63529388fabcbe1a4fc737a 100644 (file)
@@ -91,6 +91,7 @@ struct _E_Video_Hwc
    E_Comp_Wl_Video_Buf *current_fb;     /* buffer which is showing on screen currently */
 
    struct wl_listener surface_viewport_listener;
+   E_Video_Hwc_Render_Fail_Cb render_fail_cb;
 
    struct
      {