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.
This commit is contained in:
Jean-Philippe Andre 2014-12-09 21:36:45 +09:00
parent f52be78699
commit 4cf2d75715
7 changed files with 166 additions and 46 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
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.
/* 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

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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