Evas GL: Automatic fallback to indirect rendering when the scene has

not changed.

Automatically fallback to indirect rendering on FBO or X11 Pixmap
if the Evas Object Image is not marked as dirty. This should
improve the performance and/or power consumption in those
rare cases where this area of the canvas needs to be redrawn
but the GL content has not changed.

@feature
This commit is contained in:
Jean-Philippe Andre 2015-03-03 16:38:52 +09:00
parent a8e79114db
commit a14492ef73
7 changed files with 130 additions and 38 deletions

View File

@ -2853,11 +2853,9 @@ evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
if (ENFN->image_native_get)
{
Evas_Native_Surface *ns;
ns = ENFN->image_native_get(ENDT, o->engine_data);
if ( (ns) &&
(ns->type == EVAS_NATIVE_SURFACE_OPENGL) &&
(ns->data.opengl.texture_id) &&
(!ns->data.opengl.framebuffer_id) )
if (ns)
{
Eina_Bool direct_renderable = EINA_FALSE;
@ -2880,6 +2878,8 @@ evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
{
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);
if (ENFN->gl_image_direct_set)
ENFN->gl_image_direct_set(output, o->engine_data, EINA_TRUE);
o->direct_render = EINA_TRUE;
}
else
@ -2919,9 +2919,28 @@ evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
else
{
// Check if the it's not dirty but it has direct rendering
if (o->direct_render)
if (o->direct_render && ENFN->image_native_get)
{
ENFN->gl_get_pixels_set(output, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
Evas_Native_Surface *ns;
ns = ENFN->image_native_get(output, o->engine_data);
if (ENFN->gl_direct_override_get)
ENFN->gl_direct_override_get(output, &direct_override, &direct_force_off);
if (ENFN->gl_surface_direct_renderable_get)
ENFN->gl_surface_direct_renderable_get(output, ns, &direct_override);
if (direct_override && !direct_force_off)
{
// always use direct rendering
ENFN->gl_get_pixels_set(output, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
}
else
{
// Auto-fallback to FBO rendering (for perf & power consumption)
o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, obj->object);
//if (ENFN->get_pixels_render_post)
//ENFN->get_pixels_render_post(output);
o->direct_render = EINA_FALSE;
}
}
}
@ -3019,9 +3038,9 @@ evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, v
// Clear out the pixel get stuff..
if (ENFN->gl_get_pixels_set)
{
ENFN->gl_get_pixels_set(output, NULL, NULL, NULL);
}
ENFN->gl_get_pixels_set(output, NULL, NULL, NULL);
if (ENFN->gl_image_direct_set)
ENFN->gl_image_direct_set(output, o->engine_data, EINA_FALSE);
Evas_Object_Protected_Data *source =
(o->cur->source ?

View File

@ -1309,6 +1309,8 @@ struct _Evas_Func
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, Eina_Bool *override);
void (*gl_image_direct_set) (void *data, void *image, Eina_Bool direct);
int (*gl_image_direct_get) (void *data, void *image);
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);

View File

@ -623,6 +623,7 @@ struct _Evas_GL_Image
unsigned char alpha : 1;
unsigned char tex_only : 1;
unsigned char locked : 1; // gl_surface_lock/unlock
unsigned char direct : 1; // evas gl direct renderable
};
struct _Evas_GL_Font_Texture

View File

@ -1690,8 +1690,16 @@ evgl_surface_create(void *eng_data, Evas_GL_Config *cfg, int w, int h)
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->gles1_indirect)
{
eina_hash_add(evgl_engine->direct_surfaces, &sfc->color_buf, sfc);
DBG("Added tex %d as direct surface: %p", sfc->color_buf, sfc);
}
else
{
eina_hash_add(evgl_engine->direct_surfaces, &sfc->gles1_sfc_native, sfc);
DBG("Added tex %d as direct surface: %p", sfc->gles1_sfc_native, sfc);
}
}
if (sfc->direct_fb_opt &&
@ -2362,7 +2370,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
if (dbg) DBG("Surface sfc %p is a normal surface.", sfc);
// Attach fbo and the buffers
if ((ctx->current_sfc != sfc) || (ctx != sfc->current_ctx))
if ((rsc->current_ctx != ctx) || (ctx->current_sfc != sfc) || (rsc->direct.rendered))
{
sfc->current_ctx = ctx;
if ((evgl_engine->direct_mem_opt) && (evgl_engine->direct_override))
@ -2469,17 +2477,24 @@ evgl_native_surface_get(EVGL_Surface *sfc, Evas_Native_Surface *ns)
return 0;
}
ns->type = EVAS_NATIVE_SURFACE_OPENGL;
ns->version = EVAS_NATIVE_SURFACE_VERSION;
ns->data.opengl.texture_id = sfc->color_buf;
ns->data.opengl.framebuffer_id = sfc->color_buf;
ns->data.opengl.x = 0;
ns->data.opengl.y = 0;
ns->data.opengl.w = sfc->w;
ns->data.opengl.h = sfc->h;
if (sfc->direct_fb_opt)
ns->data.opengl.framebuffer_id = 0;
if (!sfc->gles1_indirect)
{
ns->type = EVAS_NATIVE_SURFACE_OPENGL;
ns->version = EVAS_NATIVE_SURFACE_VERSION;
ns->data.opengl.texture_id = sfc->color_buf;
ns->data.opengl.framebuffer_id = sfc->color_buf;
ns->data.opengl.x = 0;
ns->data.opengl.y = 0;
ns->data.opengl.w = sfc->w;
ns->data.opengl.h = sfc->h;
}
else
{
ns->type = EVAS_NATIVE_SURFACE_X11;
ns->version = EVAS_NATIVE_SURFACE_VERSION;
ns->data.x11.pixmap = (unsigned long)(intptr_t)sfc->gles1_sfc_native;
ns->data.x11.visual = sfc->gles1_sfc_visual;
}
return 1;
}
@ -2503,24 +2518,42 @@ Eina_Bool
evgl_native_surface_direct_opts_get(Evas_Native_Surface *ns,
Eina_Bool *direct_render,
Eina_Bool *client_side_rotation,
Eina_Bool *override)
Eina_Bool *direct_override)
{
EVGL_Surface *sfc;
if (override) *override = EINA_FALSE;
if (direct_render) *direct_render = EINA_FALSE;
if (direct_override) *direct_override = 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;
if (!ns) return EINA_FALSE;
sfc = eina_hash_find(evgl_engine->direct_surfaces, &ns->data.opengl.texture_id);
if (!sfc)
if (ns->type == EVAS_NATIVE_SURFACE_OPENGL &&
ns->data.opengl.texture_id)
{
DBG("Native surface %p (color_buf %d) was not found.",
ns, ns->data.opengl.texture_id);
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;
}
}
else if (ns->type == EVAS_NATIVE_SURFACE_X11 &&
ns->data.x11.pixmap)
{
sfc = eina_hash_find(evgl_engine->direct_surfaces, &ns->data.x11.pixmap);
if (!sfc)
{
DBG("Native surface %p (pixmap %x) was not found.",
ns, ns->data.x11.pixmap);
return EINA_FALSE;
}
}
else
{
ERR("Only EVAS_NATIVE_SURFACE_OPENGL or EVAS_NATIVE_SURFACE_X11 can be used for direct rendering");
return EINA_FALSE;
}
@ -2532,7 +2565,7 @@ evgl_native_surface_direct_opts_get(Evas_Native_Surface *ns,
}
if (direct_render) *direct_render = sfc->direct_fb_opt;
if (override) *override |= sfc->direct_override;
if (direct_override) *direct_override |= sfc->direct_override;
if (client_side_rotation) *client_side_rotation = sfc->client_side_rotation;
return EINA_TRUE;
}

View File

@ -47,7 +47,7 @@ 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,
Eina_Bool *override);
Eina_Bool *direct_override);
void evgl_direct_partial_info_set(int pres);
void evgl_direct_partial_info_clear();

View File

@ -28,6 +28,8 @@
static int _evas_engine_GL_log_dom = -1;
static int eng_gl_image_direct_get(void *data EINA_UNUSED, void *image);
static void
eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h, Eina_Bool do_async EINA_UNUSED)
{
@ -817,10 +819,10 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x,
gl_context = re->window_gl_context_get(re->software.ob);
re->window_use(re->software.ob);
if ((n) && (n->type == EVAS_NATIVE_SURFACE_OPENGL) &&
(n->data.opengl.framebuffer_id == 0) &&
re->func.get_pixels)
if (eng_gl_image_direct_get(data, image))
{
unsigned int texid;
gl_context->dc = context;
if ((gl_context->master_clip.enabled) &&
(gl_context->master_clip.w > 0) &&
@ -830,6 +832,16 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x,
evgl_direct_partial_info_set(gl_context->preserve_bit);
}
if (n->type == EVAS_NATIVE_SURFACE_OPENGL)
texid = n->data.opengl.texture_id;
else if (n->type == EVAS_NATIVE_SURFACE_X11)
texid = n->data.x11.pixmap;
else
{
ERR("This native surface type is not supported for direct rendering");
return EINA_FALSE;
}
// Set necessary info for direct rendering
evgl_direct_info_set(gl_context->w,
gl_context->h,
@ -839,7 +851,7 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x,
gl_context->dc->clip.y,
gl_context->dc->clip.w,
gl_context->dc->clip.h,
n->data.opengl.texture_id);
texid);
// Call pixel get function
re->func.get_pixels(re->func.get_pixels_data, re->func.obj);
@ -1533,6 +1545,27 @@ eng_gl_surface_query(void *data, void *surface, int attr, void *value)
#endif
}
static int
eng_gl_image_direct_get(void *data EINA_UNUSED, void *image)
{
Evas_GL_Image *im = image;
if (!im) return EINA_FALSE;
return im->direct;
}
static void
eng_gl_image_direct_set(void *data, void *image, Eina_Bool direct)
{
Render_Engine_GL_Generic *re = data;
Evas_GL_Image *im = image;
if (!im) return;
if (im->native.data && direct && re && re->func.get_pixels)
im->direct = EINA_TRUE;
else
im->direct = EINA_FALSE;
}
//--------------------------------//
static int
@ -2114,6 +2147,8 @@ module_open(Evas_Module *em)
// gl_current_context_get is in engine
ORD(gl_current_surface_get);
ORD(gl_rotation_angle_get);
ORD(gl_image_direct_get);
ORD(gl_image_direct_set);
ORD(image_load_error_get);

View File

@ -3572,6 +3572,8 @@ static Evas_Func func =
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
NULL, // need software mesa for gl rendering <- gl_image_direct_set
NULL, // need software mesa for gl rendering <- gl_image_direct_get
eng_image_load_error_get,
eng_font_run_font_end_get,
eng_image_animated_get,