evas filters: Avoid creating input buffer for images

When the filtered object is an image, without borders, map,
fill info or anything of this sort, then the filter input
buffer is really just a copy of the original image. We can
skip that to save on memory usage and pixel fetches.
This commit is contained in:
Jean-Philippe Andre 2017-04-03 15:34:10 +09:00
parent 45548e8358
commit 293438111c
3 changed files with 79 additions and 3 deletions

View File

@ -1719,6 +1719,35 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_state_prepare(
state->scale = obj->cur->scale;
}
static inline Eina_Bool
_image_has_border(Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_Image_Data *o)
{
return o->cur->border.l || o->cur->border.r || o->cur->border.t ||
o->cur->border.b || (o->cur->border.fill == 0);
}
static inline Eina_Bool
_image_has_map(Evas_Object_Protected_Data *obj, Evas_Image_Data *o EINA_UNUSED)
{
return ((obj->map->cur.map) && (obj->map->cur.map->count > 3) && (obj->map->cur.usemap));
}
static inline Eina_Bool
_image_is_filled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
if (o->filled) return EINA_TRUE;
return !o->cur->fill.x && !o->cur->fill.y &&
(o->cur->fill.w == obj->cur->geometry.w) &&
(o->cur->fill.h == obj->cur->geometry.h);
}
static inline Eina_Bool
_image_is_scaled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
{
return ((obj->cur->geometry.w != o->cur->image.w) ||
(obj->cur->geometry.h != o->cur->image.h));
}
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 EINA_UNUSED,
@ -1728,12 +1757,26 @@ _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Filter_Context *filter = _filter;
void *surface, *output, *ctx;
Eina_Bool ok;
int W, H;
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
output = ENDT;
// FIXME: In GL we could use the image even if scaled
if (!_image_has_border(obj, o) && !_image_has_map(obj, o) && _image_is_filled(obj, o)
&& !_image_is_scaled(obj, o))
{
int imagew, imageh, uvw, uvh;
surface = _evas_image_pixels_get(eo_obj, obj, output, NULL, NULL, x, y,
&imagew, &imageh, &uvw, &uvh, EINA_FALSE, EINA_FALSE);
ok = evas_filter_buffer_backing_set(filter, EVAS_FILTER_BUFFER_INPUT_ID, surface);
if (ok) return 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);

View File

@ -365,8 +365,11 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
continue;
}
render |= (fb->id == EVAS_FILTER_BUFFER_INPUT_ID);
render |= fb->is_render || fb->transient;
// Skip input buffer, allocate it in input render phase
if (fb->id == EVAS_FILTER_BUFFER_INPUT_ID)
continue;
render = fb->is_render || fb->transient;
draw |= (fb->id == EVAS_FILTER_BUFFER_OUTPUT_ID);
fb->buffer = _ector_buffer_create(fb, render, draw);
@ -510,12 +513,41 @@ evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid, Eina_Bool re
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return NULL;
if (!fb->buffer)
evas_filter_buffer_backing_set(ctx, bufid, NULL);
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
evas_filter_buffer_backing_set(Evas_Filter_Context *ctx, int bufid,
void *engine_buffer)
{
Evas_Filter_Buffer *fb;
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return EINA_FALSE;
EINA_SAFETY_ON_FALSE_RETURN_VAL(!fb->buffer, EINA_FALSE);
if (!engine_buffer)
{
fb->buffer = _ector_buffer_create(fb, fb->is_render, EINA_FALSE);
XDBG("Allocated buffer #%d of size %ux%u %s: %p",
fb->id, fb->w, fb->h, fb->alpha_only ? "alpha" : "rgba", fb->buffer);
return fb->buffer ? EINA_TRUE : EINA_FALSE;
}
if (fb->buffer) return EINA_FALSE;
if (fb->is_render) return EINA_FALSE;
fb->buffer = ENFN->ector_buffer_wrap(ENDT, ctx->evas->evas, engine_buffer);
return EINA_TRUE;
}
Eina_Bool
evas_filter_buffer_backing_release(Evas_Filter_Context *ctx,
void *stolen_buffer)
@ -1558,7 +1590,7 @@ evas_filter_font_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
fb = _filter_buffer_get(ctx, bufid);
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
surface = evas_ector_buffer_render_image_get(fb->buffer);
surface = evas_filter_buffer_backing_get(ctx, bufid, EINA_TRUE);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
// Copied from evas_font_draw_async_check

View File

@ -158,6 +158,7 @@ void evas_filter_context_obscured_region_set(Evas_Filter_Con
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only);
int evas_filter_buffer_proxy_new(Evas_Filter_Context *ctx, Evas_Filter_Proxy_Binding *pb, int *w, int *h);
void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid, Eina_Bool render);
Eina_Bool evas_filter_buffer_backing_set(Evas_Filter_Context *ctx, int bufid, void *engine_buffer);
Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer);
Eina_Bool evas_filter_context_run(Evas_Filter_Context *ctx);