evas filters: Avoid unnecessary draw

This avoids creating one more FBO and doing one more draw,
by rendering the image input data directly into the input
buffer. This also makes the code common between SW and GL.
This commit is contained in:
Jean-Philippe Andre 2017-03-22 16:16:22 +09:00
parent ebeead4681
commit b77cb960ca
6 changed files with 26 additions and 76 deletions

View File

@ -54,7 +54,7 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj,
else
{
Evas_Object_Filter_Data *fcow;
void *output = evas_filter_buffer_backing_steal(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
void *output = evas_filter_buffer_backing_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID, EINA_FALSE);
fcow = FCOW_BEGIN(pd);
fcow->output = output;

View File

@ -1754,30 +1754,22 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_state_prepare(
EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
Eo *eo_obj, Evas_Image_Data *o, void *_filter, void *context,
Eo *eo_obj, Evas_Image_Data *o, void *_filter, void *context EINA_UNUSED,
void *data EINA_UNUSED, int l, int r EINA_UNUSED, int t, int b EINA_UNUSED,
int x, int y, Eina_Bool do_async)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Filter_Context *filter = _filter;
void *surface, *output;
Eina_Bool input_stolen;
void *surface, *output, *ctx;
int W, H;
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
output = ENDT;
if (ENFN->gl_surface_read_pixels)
{
surface = ENFN->image_map_surface_new(output, W, H, EINA_TRUE);
input_stolen = EINA_FALSE;
}
else
{
surface = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_INPUT_ID);
input_stolen = EINA_TRUE;
}
surface = evas_filter_buffer_backing_get(filter, EVAS_FILTER_BUFFER_INPUT_ID, EINA_TRUE);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
if (!o->filled)
{
l = 0;
@ -1786,30 +1778,25 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
b = 0;
}
if (!surface)
ctx = ENFN->context_new(output);
if (o->cur->has_alpha && !obj->cur->snapshot)
{
ERR("Failed to allocate surface for filter input!");
return EINA_FALSE;
ENFN->context_color_set(output, ctx, 0, 0, 0, 0);
ENFN->context_render_op_set(output, ctx, EVAS_RENDER_COPY);
ENFN->rectangle_draw(output, ctx, surface, 0, 0, W, H, do_async);
ENFN->context_color_set(output, ctx, 255, 255, 255, 255);
ENFN->context_render_op_set(output, ctx, EVAS_RENDER_BLEND);
}
ENFN->context_color_set(output, context, 0, 0, 0, 0);
ENFN->context_render_op_set(output, context, EVAS_RENDER_COPY);
ENFN->rectangle_draw(output, context, surface, 0, 0, W, H, EINA_FALSE);
ENFN->context_color_set(output, context, 255, 255, 255, 255);
ENFN->context_render_op_set(output, context, EVAS_RENDER_BLEND);
_evas_image_render(eo_obj, obj, output, context, surface,
_evas_image_render(eo_obj, obj, output, ctx, surface,
x + l - obj->cur->geometry.x,
y + t - obj->cur->geometry.y,
l, t, r, b, do_async);
if (!input_stolen)
{
evas_filter_image_draw(filter, context, EVAS_FILTER_BUFFER_INPUT_ID, surface, do_async);
ENFN->image_free(output, surface);
}
else
evas_filter_buffer_backing_release(filter, surface);
ENFN->context_free(output, ctx);
evas_filter_buffer_backing_release(filter, surface);
return EINA_TRUE;
}

View File

@ -13002,7 +13002,7 @@ _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success)
if (filter->ti)
{
filter->output = evas_filter_buffer_backing_steal(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
filter->output = evas_filter_buffer_backing_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID, EINA_FALSE);
if (filter->ti->parent.format->gfx_filter)
filter->ti->parent.format->gfx_filter->invalid = !success;
// else just avoid sigsegv

View File

@ -395,14 +395,17 @@ _filter_buffer_get(Evas_Filter_Context *ctx, int bufid)
}
void *
evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid, Eina_Bool render)
{
Evas_Filter_Buffer *fb;
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return NULL;
return evas_ector_buffer_drawable_image_get(fb->buffer);
if (render)
return evas_ector_buffer_render_image_get(fb->buffer); // ref++
else
return evas_ector_buffer_drawable_image_get(fb->buffer); // ref++
}
Eina_Bool
@ -413,7 +416,7 @@ evas_filter_buffer_backing_release(Evas_Filter_Context *ctx,
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_main_loop_is(), EINA_FALSE);
ENFN->image_free(ENDT, stolen_buffer);
ENFN->image_free(ENDT, stolen_buffer); // ref--
return EINA_TRUE;
}
@ -1445,44 +1448,6 @@ evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
return EINA_TRUE;
}
/* Image draw: scale and draw an original image into a RW surface */
Eina_Bool
evas_filter_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
void *image, Eina_Bool do_async)
{
int dw = 0, dh = 0, w = 0, h = 0;
Eina_Bool async_unref;
Evas_Filter_Buffer *fb;
void *surface;
ENFN->image_size_get(ENDT, image, &w, &h);
if (!w || !h) return EINA_FALSE;
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return EINA_FALSE;
surface = evas_ector_buffer_render_image_get(fb->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
ENFN->image_size_get(ENDT, image, &dw, &dh);
if (!dw || !dh) return EINA_FALSE;
async_unref = ENFN->image_draw(ENDT, draw_context, surface, image,
0, 0, w, h,
0, 0, dw, dh,
EINA_TRUE, do_async);
if (do_async && async_unref)
{
ENFN->image_ref(ENDT, image);
evas_unref_queue_image_put(ctx->evas, image);
}
evas_ector_buffer_engine_image_release(fb->buffer, surface);
return EINA_TRUE;
}
/* Clip full input rect (0, 0, sw, sh) to target (dx, dy, dw, dh)
* and get source's clipped sx, sy as well as destination x, y, cols and rows */
void

View File

@ -252,7 +252,6 @@ struct _Evas_Filter_Buffer
Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)
Eina_Bool transient : 1; // temporary buffer (automatic allocation)
Eina_Bool locked : 1; // internal flag
Eina_Bool delete_me : 1; // request delete asap (after released by client)
Eina_Bool dirty : 1; // Marked as dirty as soon as a command writes to it
Eina_Bool is_render : 1; // Is render target of a filter using engine functions (ie. needs FBO in GL)
};

View File

@ -155,13 +155,12 @@ Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Co
void evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle rect);
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
void *evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid);
void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid, Eina_Bool render);
Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer);
Eina_Bool evas_filter_run(Evas_Filter_Context *ctx);
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_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid, void *image, Eina_Bool do_async);
Eina_Bool evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, void *surface, int x, int y);
// utility function