From b77cb960caa4f5fee153331d6e7f5ebcf72b722c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 22 Mar 2017 16:16:22 +0900 Subject: [PATCH] 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. --- src/lib/evas/canvas/evas_filter_mixin.c | 2 +- src/lib/evas/canvas/evas_object_image.c | 47 +++++++++++------------------ src/lib/evas/canvas/evas_object_textblock.c | 2 +- src/lib/evas/filters/evas_filter.c | 47 ++++------------------------- src/lib/evas/filters/evas_filter_private.h | 1 - src/lib/evas/include/evas_filter.h | 3 +- 6 files changed, 26 insertions(+), 76 deletions(-) diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index ce160a8..45db424 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -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; diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index a3f7e48..46bfd33 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -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; } diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index f021649..05166b9 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -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 diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index f6e1e27..46442ae 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -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 diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index e61b01b..c62262a 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -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) }; diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index 34a09c4..c6854fd 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -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 -- 2.7.4