From: Seunghun Lee Date: Fri, 10 Jan 2020 08:05:36 +0000 (+0900) Subject: video: Using fallback rendering path in case rendering using hwc has been failed. X-Git-Tag: submit/tizen/20200116.021659^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=028117c73f51a45ad899f64cec92629f8ac09360;p=platform%2Fupstream%2Fenlightenment.git video: Using fallback rendering path in case rendering using hwc has been failed. 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 --- diff --git a/src/bin/video/e_client_video.c b/src/bin/video/e_client_video.c index 11adb20500..67c003b855 100644 --- a/src/bin/video/e_client_video.c +++ b/src/bin/video/e_client_video.c @@ -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: diff --git a/src/bin/video/e_video_internal.h b/src/bin/video/e_video_internal.h index 34ae748bc0..bc7f743320 100644 --- a/src/bin/video/e_video_internal.h +++ b/src/bin/video/e_video_internal.h @@ -40,6 +40,10 @@ 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 diff --git a/src/bin/video/iface/e_video_fallback.c b/src/bin/video/iface/e_video_fallback.c index ad35ba9f12..cbc2f997e7 100644 --- a/src/bin/video/iface/e_video_fallback.c +++ b/src/bin/video/iface/e_video_fallback.c @@ -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) diff --git a/src/bin/video/iface/e_video_hwc.c b/src/bin/video/iface/e_video_hwc.c index dbe1d2e24c..93fdcce9cf 100644 --- a/src/bin/video/iface/e_video_hwc.c +++ b/src/bin/video/iface/e_video_hwc.c @@ -14,9 +14,10 @@ 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; +} diff --git a/src/bin/video/iface/e_video_hwc.h b/src/bin/video/iface/e_video_hwc.h index e414207a69..16f0f164ae 100644 --- a/src/bin/video/iface/e_video_hwc.h +++ b/src/bin/video/iface/e_video_hwc.h @@ -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 {