jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=4cf2d75715d6d9c3bc7f02a246997b0ca7a330cd
commit 4cf2d75715d6d9c3bc7f02a246997b0ca7a330cd Author: Jean-Philippe Andre <jp.an...@samsung.com> Date: Tue Dec 9 21:36:45 2014 +0900 Evas GL: Fix direct rendering with client-side rotation There was a problem when checking whether the current surface is compatible with direct rendering. In case of client-side rotation (it's a flag set on the surface by the app), a surface can be directly rendered even if the rotation is not 0. But, before this patch, it was assumed that the surface was current. Which doesn't make sense because make_current is called by the pixel callback, from the application, and this happens *after* we check for direct rendering. As a consequence, it was not possible to mix directly rendered surfaces with FBO-based ones, and use client-side rotation. This patch should solve that issue. --- src/lib/evas/canvas/evas_object_image.c | 20 +-- src/lib/evas/include/evas_private.h | 1 + src/modules/evas/engines/gl_common/evas_gl_core.c | 154 ++++++++++++++++----- src/modules/evas/engines/gl_common/evas_gl_core.h | 7 +- .../evas/engines/gl_common/evas_gl_core_private.h | 3 + src/modules/evas/engines/gl_generic/evas_engine.c | 26 +++- .../evas/engines/software_generic/evas_engine.c | 3 +- 7 files changed, 167 insertions(+), 47 deletions(-) diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index fdd7161..ce03b71 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -2759,25 +2759,27 @@ evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, (ns->data.opengl.texture_id) && (!ns->data.opengl.framebuffer_id) ) { + Eina_Bool direct_renderable = EINA_FALSE; + // Check if we can do direct rendering... if (ENFN->gl_direct_override_get) ENFN->gl_direct_override_get(output, &direct_override, &direct_force_off); - if ( (((obj->cur->geometry.w == o->cur->image.w) && + if (ENFN->gl_surface_direct_renderable_get) + direct_renderable = ENFN->gl_surface_direct_renderable_get(output, ns); + + if ( ((direct_override) || + ((direct_renderable) && + (obj->cur->geometry.w == o->cur->image.w) && (obj->cur->geometry.h == o->cur->image.h) && (obj->cur->color.r == 255) && (obj->cur->color.g == 255) && (obj->cur->color.b == 255) && (obj->cur->color.a == 255) && - (!obj->map->cur.map)) || - (direct_override)) && - (!direct_force_off) ) + (!obj->map->cur.map)) + ) && (!direct_force_off) ) { - if (ENFN->gl_get_pixels_set) - { - ENFN->gl_get_pixels_set(output, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj); - } - + ENFN->gl_get_pixels_set(output, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj); o->direct_render = EINA_TRUE; } else diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 4f057c9..c00cc50 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1273,6 +1273,7 @@ struct _Evas_Func void *(*gl_current_surface_get) (void *data); int (*gl_rotation_angle_get) (void *data); Eina_Bool (*gl_surface_query) (void *data, void *surface, int attr, void *value); + Eina_Bool (*gl_surface_direct_renderable_get) (void *data, Evas_Native_Surface *ns); int (*image_load_error_get) (void *data, void *image); int (*font_run_end_get) (void *data, Evas_Font_Set *font, Evas_Font_Instance **script_fi, Evas_Font_Instance **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len); diff --git a/src/modules/evas/engines/gl_common/evas_gl_core.c b/src/modules/evas/engines/gl_common/evas_gl_core.c index c0d7a2b..9d58f02 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_core.c +++ b/src/modules/evas/engines/gl_common/evas_gl_core.c @@ -1111,7 +1111,7 @@ _internal_config_set(EVGL_Surface *sfc, Evas_GL_Config *cfg) // TODO: Implement surface reconfigure and add depth+stencil support // Direct Rendering Option - if ((!depth_bit && !stencil_bit) || evgl_engine->direct_override) + if ((!depth_bit && !stencil_bit && !msaa_samples) || evgl_engine->direct_override) sfc->direct_fb_opt = cfg->options_bits & EVAS_GL_OPTIONS_DIRECT; // Extra flags for direct rendering @@ -1271,6 +1271,27 @@ _evgl_not_in_pixel_get(void) EVGL_Context *ctx = rsc->current_ctx; + if (evgl_engine->direct_force_off) + return 0; + + if (rsc->id != evgl_engine->main_tid) + return 0; + + if (!ctx || !ctx->current_sfc) + return 0; + + if (!ctx->current_sfc->direct_fb_opt) + return 0; + + if (rsc->direct.rot == 0) + return !rsc->direct.enabled; + + if (!ctx->current_sfc->client_side_rotation) + return 0; + + return !rsc->direct.enabled; + + /* was: if ((!evgl_engine->direct_force_off) && (rsc->id == evgl_engine->main_tid) && (ctx) && @@ -1280,6 +1301,7 @@ _evgl_not_in_pixel_get(void) return 1; else return 0; + */ } int @@ -1354,6 +1376,7 @@ EVGL_Engine * evgl_engine_init(void *eng_data, const EVGL_Interface *efunc) { int direct_mem_opt = 0, direct_off = 0, direct_soff = 0, debug_mode = 0; + int direct_override = 0; char *s = NULL; if (evgl_engine) return evgl_engine; @@ -1436,6 +1459,12 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc) if (direct_mem_opt == 1) evgl_engine->direct_mem_opt = 1; + // Check for Direct rendering override env var. + s = getenv("EVAS_GL_DIRECT_OVERRIDE"); + if (s) direct_override = atoi(s); + if (direct_override == 1) + evgl_engine->direct_override = 1; + // Check if Direct Rendering Override Force Off flag is on s = getenv("EVAS_GL_DIRECT_OVERRIDE_FORCE_OFF"); if (s) direct_off = atoi(s); @@ -1461,6 +1490,9 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc) if (!gl_funcs) gl_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); if (!gles1_funcs) gles1_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); + // Direct surfaces map texid->Evas_GL_Surface + evgl_engine->direct_surfaces = eina_hash_int32_new(NULL); + return evgl_engine; error: @@ -1496,6 +1528,12 @@ evgl_engine_shutdown(void *eng_data) // Destroy internal resources _evgl_tls_resource_destroy(eng_data); + if (evgl_engine->direct_surfaces) + { + eina_hash_free(evgl_engine->direct_surfaces); + evgl_engine->direct_surfaces = NULL; + } + LKD(evgl_engine->resource_lock); // Free engine @@ -1507,8 +1545,6 @@ void * evgl_surface_create(void *eng_data, Evas_GL_Config *cfg, int w, int h) { EVGL_Surface *sfc = NULL; - char *s = NULL; - int direct_override = 0, direct_mem_opt = 0; Eina_Bool need_reconfigure = EINA_FALSE; Eina_Bool dbg; @@ -1537,25 +1573,6 @@ evgl_surface_create(void *eng_data, Evas_GL_Config *cfg, int w, int h) return NULL; } - // Check for Direct rendering override env var. - if (!evgl_engine->direct_override) - if ((s = getenv("EVAS_GL_DIRECT_OVERRIDE"))) - { - direct_override = atoi(s); - if (direct_override == 1) - evgl_engine->direct_override = 1; - } - - // Check if Direct Rendering Memory Optimzation flag is on - // Creates resources on demand when it fallsback to fbo rendering - if (!evgl_engine->direct_mem_opt) - if ((s = getenv("EVAS_GL_DIRECT_MEM_OPT"))) - { - direct_mem_opt = atoi(s); - if (direct_mem_opt == 1) - evgl_engine->direct_mem_opt = 1; - } - // Allocate surface structure sfc = calloc(1, sizeof(EVGL_Surface)); if (!sfc) @@ -1629,6 +1646,12 @@ evgl_surface_create(void *eng_data, Evas_GL_Config *cfg, int w, int h) LKL(evgl_engine->resource_lock); evgl_engine->surfaces = eina_list_prepend(evgl_engine->surfaces, sfc); + if (sfc->direct_fb_opt) + { + eina_hash_add(evgl_engine->direct_surfaces, &sfc->color_buf, sfc); + DBG("Added tex %d as direct surface: %p", sfc->color_buf, sfc); + } + if (sfc->direct_fb_opt && (sfc->depth_fmt || sfc->stencil_fmt || sfc->depth_stencil_fmt)) { @@ -1776,6 +1799,7 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc) EVGL_Resource *rsc; Eina_Bool need_reconfigure = EINA_FALSE; Eina_Bool dbg; + GLuint texid; // FIXME: This does some make_current(0,0) which may have side effects @@ -1842,6 +1866,7 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc) // Destroy created buffers + texid = sfc->color_buf; if (!_surface_buffers_destroy(sfc)) { ERR("Error deleting surface resources."); @@ -1875,6 +1900,12 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc) LKL(evgl_engine->resource_lock); evgl_engine->surfaces = eina_list_remove(evgl_engine->surfaces, sfc); + if (sfc->direct_fb_opt) + { + eina_hash_del(evgl_engine->direct_surfaces, &texid, sfc); + DBG("Removed tex %d from the direct surface: %p", texid, sfc); + } + if (sfc->direct_fb_opt && (sfc->depth_fmt || sfc->stencil_fmt || sfc->depth_stencil_fmt)) { @@ -2369,23 +2400,77 @@ evgl_direct_rendered() return rsc->direct.rendered; } +/* + * This function can tell the engine whether a surface can be directly + * rendered to the Evas, despite any window rotation. For that purpose, + * we let the engine know the surface flags for this texture + */ +Eina_Bool +evgl_native_surface_direct_opts_get(Evas_Native_Surface *ns, + Eina_Bool *direct_render, + Eina_Bool *client_side_rotation) +{ + EVGL_Surface *sfc; + + if (direct_render) *direct_render = EINA_FALSE; + if (client_side_rotation) *client_side_rotation = EINA_FALSE; + + if (!evgl_engine) return EINA_FALSE; + if (!ns || (ns->type != EVAS_NATIVE_SURFACE_OPENGL)) return EINA_FALSE; + if (ns->data.opengl.framebuffer_id != 0) return EINA_FALSE; + if (ns->data.opengl.texture_id == 0) return EINA_FALSE; + + sfc = eina_hash_find(evgl_engine->direct_surfaces, &ns->data.opengl.texture_id); + if (!sfc) + { + DBG("Native surface %p (color_buf %d) was not found.", + ns, ns->data.opengl.texture_id); + return EINA_FALSE; + } + + if (evgl_engine->api_debug_mode) + { + DBG("Found native surface: texid:%u DR:%d CSR:%d", + ns->data.opengl.texture_id, (int) sfc->direct_fb_opt, + (int) sfc->client_side_rotation); + } + + if (direct_render) *direct_render = sfc->direct_fb_opt; + if (client_side_rotation) *client_side_rotation = sfc->client_side_rotation; + return EINA_TRUE; +} + void evgl_direct_info_set(int win_w, int win_h, int rot, int img_x, int img_y, int img_w, int img_h, - int clip_x, int clip_y, int clip_w, int clip_h) + int clip_x, int clip_y, int clip_w, int clip_h, + unsigned int texid) { EVGL_Resource *rsc; + EVGL_Surface *sfc; - if (!(rsc=_evgl_tls_resource_get())) return; - - /* Normally direct rendering isn't allowed if rotation is not 0. - * BUT, if client_side_rotation or override is on, allow it. + if (!(rsc = _evgl_tls_resource_get())) + return; + + /* Check for direct rendering + * + * DR is allowed iif: + * - Rotation == 0 + * OR: - Client-Side Rotation is set on the surface + * - Direct Override is set + * + * If the surface is not found, we assume indirect rendering. */ - if ((rot == 0) || evgl_engine->direct_override || - (rsc->current_ctx && - rsc->current_ctx->current_sfc && - rsc->current_ctx->current_sfc->client_side_rotation)) + + sfc = eina_hash_find(evgl_engine->direct_surfaces, &texid); + + if ((rot == 0) || + evgl_engine->direct_override || + (sfc && sfc->client_side_rotation)) { + if (evgl_engine->api_debug_mode) + DBG("Direct rendering is enabled."); + rsc->direct.enabled = EINA_TRUE; rsc->direct.win_w = win_w; @@ -2404,6 +2489,9 @@ evgl_direct_info_set(int win_w, int win_h, int rot, } else { + if (evgl_engine->api_debug_mode) + DBG("Direct rendering is disabled."); + rsc->direct.enabled = EINA_FALSE; } } @@ -2459,8 +2547,8 @@ evgl_direct_partial_info_clear() void evgl_direct_override_get(int *override, int *force_off) { - *override = evgl_engine->direct_override; - *force_off = evgl_engine->direct_force_off; + if (override) *override = evgl_engine->direct_override; + if (force_off) *force_off = evgl_engine->direct_force_off; } void diff --git a/src/modules/evas/engines/gl_common/evas_gl_core.h b/src/modules/evas/engines/gl_common/evas_gl_core.h index f74a9c1..9dcb5bb 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_core.h +++ b/src/modules/evas/engines/gl_common/evas_gl_core.h @@ -40,9 +40,14 @@ int evgl_direct_rendered(); void evgl_direct_override_get(int *override, int *force_off); void evgl_direct_info_set(int win_w, int win_h, int rot, int img_x, int img_y, int img_w, int img_h, - int clip_x, int clip_y, int clip_w, int clip_h); + int clip_x, int clip_y, int clip_w, int clip_h, + unsigned int texid); void evgl_direct_info_clear(); +Eina_Bool evgl_native_surface_direct_opts_get(Evas_Native_Surface *ns, + Eina_Bool *direct_render, + Eina_Bool *client_side_rotation); + void evgl_direct_partial_info_set(int pres); void evgl_direct_partial_info_clear(); void evgl_direct_partial_render_start(); diff --git a/src/modules/evas/engines/gl_common/evas_gl_core_private.h b/src/modules/evas/engines/gl_common/evas_gl_core_private.h index ec30529..a13d369 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_core_private.h +++ b/src/modules/evas/engines/gl_common/evas_gl_core_private.h @@ -294,6 +294,8 @@ struct _EVGL_Engine int direct_override; int direct_mem_opt; + + // Add more debug logs (DBG levels 4 and 6) int api_debug_mode; // Force Off for Debug purposes @@ -305,6 +307,7 @@ struct _EVGL_Engine // Keep track of all the current surfaces/contexts Eina_List *surfaces; Eina_List *contexts; + Eina_Hash *direct_surfaces; // unsigned (texid) --> EVGL_Surface* Eina_List *direct_depth_stencil_surfaces; //void *engine_data; diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 6371fe7..45d35ea 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -818,8 +818,6 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, (n->data.opengl.framebuffer_id == 0) && re->func.get_pixels) { - DBG("Rendering Directly to the window: %p", data); - gl_context->dc = context; if ((gl_context->master_clip.enabled) && (gl_context->master_clip.w > 0) && @@ -837,7 +835,8 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, gl_context->dc->clip.x, gl_context->dc->clip.y, gl_context->dc->clip.w, - gl_context->dc->clip.h); + gl_context->dc->clip.h, + n->data.opengl.texture_id); // Call pixel get function re->func.get_pixels(re->func.get_pixels_data, re->func.obj); @@ -1245,6 +1244,26 @@ eng_gl_direct_override_get(void *data, int *override, int *force_off) evgl_direct_override_get(override, force_off); } +static Eina_Bool +eng_gl_surface_direct_renderable_get(void *data, Evas_Native_Surface *ns) +{ + Render_Engine_GL_Generic *re = data; + Eina_Bool direct_render, client_side_rotation; + + EVGLINIT(data, EINA_FALSE); + if (!re || !ns) return EINA_FALSE; + if (!evgl_native_surface_direct_opts_get(ns, &direct_render, &client_side_rotation)) + return EINA_FALSE; + + if (!direct_render) + return EINA_FALSE; + + if ((re->software.outbuf_get_rot(re->software.ob) != 0) && (!client_side_rotation)) + return EINA_FALSE; + + return EINA_TRUE; +} + static void eng_gl_get_pixels_set(void *data, void *get_pixels, void *get_pixels_data, void *obj) { @@ -1926,6 +1945,7 @@ module_open(Evas_Module *em) ORD(gl_native_surface_get); ORD(gl_api_get); ORD(gl_direct_override_get); + ORD(gl_surface_direct_renderable_get); ORD(gl_get_pixels_set); ORD(gl_surface_lock); ORD(gl_surface_read_pixels); diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index f2a355a..ac9e086 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -3098,6 +3098,7 @@ static Evas_Func func = NULL, // need software mesa for gl rendering <- gl_current_surface_get NULL, // need software mesa for gl rendering <- gl_rotation_angle_get NULL, // need software mesa for gl rendering <- gl_surface_query + NULL, // need software mesa for gl rendering <- gl_surface_direct_renderable_get eng_image_load_error_get, eng_font_run_font_end_get, eng_image_animated_get, @@ -3106,7 +3107,7 @@ static Evas_Func func = eng_image_animated_loop_count_get, eng_image_animated_frame_duration_get, eng_image_animated_frame_set, - NULL, + NULL, // image_max_size_get eng_multi_font_draw, eng_pixel_alpha_get, NULL, // eng_context_flush - software doesn't use it --