Evas filters: OpenGL support part 2.

This patch implements the final draw from RGBA_Image to the
OpenGL surface. We can even steal the output buffer and
redraw it quickly, without having to re-render everything
(same as in SW).
This commit is contained in:
Jean-Philippe Andre 2014-01-17 15:05:23 +09:00
parent f007cd5665
commit 8062df320c
4 changed files with 103 additions and 30 deletions

View File

@ -2128,12 +2128,9 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
{
int X, Y, W, H;
Evas_Filter_Context *filter;
int inbuf = 1;
int outbuf = 2;
int targetbuf;
RGBA_Image *input, *outputimg = NULL; // FIXME: This is engine dependent
const int inbuf = 1;
const int outbuf = 2;
void *filter_ctx;
static int gl_engine = -1;
Eina_Bool ok;
int ox = 0, oy = 0;
@ -2144,10 +2141,6 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
* image to GL.
*/
// FIXME. Disabled redraw for OpenGL.
if (gl_engine == -1)
gl_engine = !!strstr(obj->layer->evas->engine.module->definition->name, "gl");
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
X = obj->cur->geometry.x;
@ -2185,7 +2178,6 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
else
{
// Render this image only
outputimg = o->cur.filter.output;
ENFN->image_draw(ENDT, context,
surface, o->cur.filter.output,
0, 0, W, H, // src
@ -2208,21 +2200,15 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
// Proxies
evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE);
// Output
targetbuf = evas_filter_buffer_image_new(filter, surface);
// Context: FIXME it should be a sw context only
filter_ctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, filter_ctx, 255, 255, 255, 255);
// Alloc input now so we can draw text asap
// Allocate main buffers now
evas_filter_buffer_data_set(filter, inbuf, NULL, W, H, EINA_TRUE);
// Allocate and steal output so we can keep it around
evas_filter_buffer_data_set(filter, outbuf, NULL, W, H, EINA_FALSE);
if (!gl_engine)
outputimg = evas_filter_buffer_backing_steal(filter, outbuf);
o->cur.filter.output = outputimg;
evas_filter_target_set(filter, context, surface, X + x, Y + y);
o->cur.filter.output = evas_filter_buffer_backing_steal(filter, outbuf);
// Render text to input buffer
EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
@ -2235,10 +2221,6 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
do_async);
}
// FIXME: This final blend is not necessary. Needs to be removed.
evas_filter_command_blend_add(filter, context, outbuf, targetbuf,
X + x, Y + y, EVAS_FILTER_FILL_MODE_NONE);
ENFN->context_free(ENDT, filter_ctx);
// Add post-run callback and run filter

View File

@ -330,7 +330,6 @@ _rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data)
}
else
{
WRN("EXPERIMENTAL OpenGL support. VERY HACKISH!");
// FIXME: Directly calling the alloc functions since we want to use sw surfaces.
if (!data)
@ -371,6 +370,9 @@ evas_filter_buffer_alloc(Evas_Filter_Buffer *fb, int w, int h)
{
int W, H;
if (fb->ctx->gl_engine)
return EINA_TRUE;
fb->ENFN->image_size_get(fb->ENDT, fb->backing, &W, &H);
if ((W == w) && (H == h))
return EINA_TRUE;
@ -526,8 +528,13 @@ evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
buffer = _filter_buffer_get(ctx, bufid);
if (!buffer) return NULL;
buffer->allocated = EINA_FALSE;
return buffer->backing;
if (!buffer->glimage)
{
buffer->allocated = EINA_FALSE;
return buffer->backing;
}
else
return buffer->glimage;
}
static Evas_Filter_Command *
@ -1211,6 +1218,78 @@ evas_filter_fill_cpu_func_get(Evas_Filter_Command *cmd)
}
/* Final target */
Eina_Bool
evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
void *surface, int x, int y)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
ctx->target.bufid = evas_filter_buffer_image_new(ctx, surface);
if (!ctx->gl_engine)
{
/* FIXME: This extraneous blend could be avoided if all filters
* drawing to output (buffer #2) support proper colors and offsets.
*/
evas_filter_command_blend_add(ctx, draw_context, 2, ctx->target.bufid,
x, y, EVAS_FILTER_FILL_MODE_NONE);
}
else
{
// Since GL has sync rendering, draw_context is safe to keep around
Evas_Filter_Buffer *target, *image;
RGBA_Image *im;
ctx->target.context = draw_context;
ctx->target.x = x;
ctx->target.y = y;
target = _filter_buffer_get(ctx, ctx->target.bufid);
target->glimage = target->backing;
target->backing = NULL;
image = _filter_buffer_get(ctx, 2);
im = image->backing;
image->glimage = ENFN->image_new_from_data
(ENDT, image->w, image->h, im->image.data, EINA_TRUE, im->cache_entry.space);
}
return EINA_TRUE;
}
static Eina_Bool
_filter_target_render(Evas_Filter_Context *ctx)
{
Evas_Filter_Buffer *src, *dst;
Eina_Bool ok;
/* FIXME: This is some hackish hook to send the final buffer on the screen
* Only used for OpenGL now, since evas_filter_target_set() adds a blend
* command in case of pure software rendering.
*/
if (!ctx->gl_engine) return EINA_FALSE;
EINA_SAFETY_ON_FALSE_RETURN_VAL(ctx->target.bufid, EINA_FALSE);
src = _filter_buffer_get(ctx, 2);
if (!src) return EINA_FALSE;
dst = _filter_buffer_get(ctx, ctx->target.bufid);
if (!dst) return EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(src->glimage, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(dst->glimage, EINA_FALSE);
ok = ENFN->image_draw(ENDT, ctx->target.context,
dst->glimage, src->glimage,
0, 0, src->w, src->h,
ctx->target.x, ctx->target.y, src->w, src->h,
EINA_TRUE, EINA_FALSE);
return ok;
}
/* Font drawing stuff */
Eina_Bool
evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
@ -1367,9 +1446,6 @@ _filter_command_run(Evas_Filter_Command *cmd)
//func = cmd->ENFN->filter_command_func_get(cmd);
// FIXME: Must call engine function, not CPU directly.
if (strncmp(cmd->ctx->evas->engine.module->definition->name, "software", 8))
WRN("EXPERIMENTAL OpenGL support! ALL HELL WILL BREAK LOOSE!");
switch (cmd->mode)
{
case EVAS_FILTER_MODE_BLEND:
@ -1436,7 +1512,9 @@ _filter_chain_run(Evas_Filter_Context *ctx)
}
}
return ok;
if (!ok) return EINA_FALSE;
return _filter_target_render(ctx);
}
static void
@ -1458,6 +1536,9 @@ evas_filter_run(Evas_Filter_Context *ctx, Eina_Bool do_async)
if (!ctx->commands)
return EINA_TRUE;
if (ctx->gl_engine)
WRN("EXPERIMENTAL OpenGL support! Might very well crash or not render anything.");
if (do_async)
{
evas_thread_cmd_enqueue(_filter_thread_run_cb, ctx);

View File

@ -57,6 +57,14 @@ struct _Evas_Filter_Context
void *data;
} post_run;
struct
{
// Only used with the GL engine.
int bufid;
void *context;
int x, y;
} target;
Eina_Bool gl_engine : 1;
};
@ -139,6 +147,7 @@ struct _Evas_Filter_Buffer
Evas_Object *source;
void *backing;
void *glimage;
int w, h;
Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)

View File

@ -113,6 +113,7 @@ Eina_Bool evas_filter_buffer_data_set(Evas_Filter_Context *ctx, i
Eina_Bool evas_filter_run(Evas_Filter_Context *ctx, Eina_Bool do_async);
Eina_Bool evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid, Evas_Font_Set *font, int x, int y, Evas_Text_Props *text_props, Eina_Bool do_async);
Eina_Bool evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, void *surface, int x, int y);
/**
* @brief Blend a source buffer into a destination buffer, allowing X,Y offsets, Alpha to RGBA conversion with color