Evas filters: Alloc/Dealloc buffers from the main loop only

This is a problem I didn't spot immediately... but with
tons of nasty consequences.
This commit is contained in:
Jean-Philippe Andre 2014-01-23 14:58:05 +09:00
parent bf46a1d26c
commit eea049f988
6 changed files with 187 additions and 76 deletions

View File

@ -2133,6 +2133,7 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
void *filter_ctx;
Eina_Bool ok;
int ox = 0, oy = 0;
Image_Entry *previous = o->cur.filter.output;
/* NOTE: Font effect rendering is now done ENTIRELY on CPU.
* So we rely on cache/cache2 to allocate a real image buffer,
@ -2146,7 +2147,7 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
X = obj->cur->geometry.x;
Y = obj->cur->geometry.y;
if (o->cur.filter.output)
if (previous)
{
Eina_Bool redraw = o->cur.filter.changed;
@ -2170,16 +2171,11 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
eina_iterator_free(it);
}
if (redraw)
{
ENFN->image_free(ENDT, o->cur.filter.output);
o->cur.filter.output = NULL;
}
else
if (!redraw)
{
// Render this image only
ENFN->image_draw(ENDT, context,
surface, o->cur.filter.output,
surface, previous,
0, 0, W, H, // src
X + x, Y + y, W, H, // dst
EINA_FALSE, // smooth
@ -2205,10 +2201,15 @@ evas_object_text_render(Evas_Object *eo_obj EINA_UNUSED,
ENFN->context_color_set(ENDT, filter_ctx, 255, 255, 255, 255);
// Allocate main buffers now
evas_filter_buffer_data_set(filter, inbuf, NULL, W, H, EINA_TRUE);
evas_filter_buffer_data_set(filter, outbuf, NULL, W, H, EINA_FALSE);
evas_filter_context_buffers_allocate_all(filter, W, H);
//evas_filter_buffer_data_set(filter, inbuf, NULL, W, H, EINA_TRUE);
//evas_filter_buffer_data_set(filter, outbuf, NULL, W, H, EINA_FALSE);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Steal output and release previous
o->cur.filter.output = evas_filter_buffer_backing_steal(filter, outbuf);
if (o->cur.filter.output != previous)
evas_filter_buffer_backing_release(filter, previous);
// Render text to input buffer
EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)

View File

@ -80,29 +80,40 @@ evas_filter_context_clear(Evas_Filter_Context *ctx)
// Note: don't reset post_run, as it it set by the client
}
static void
_backing_free(Evas_Filter_Context *ctx, Image_Entry *ie)
{
if (!ie) return;
if (!ctx->gl_engine)
ENFN->image_free(ENDT, ie);
else
{
if (!evas_cserve2_use_get())
evas_cache_image_drop(ie);
else
evas_cache2_image_close(ie);
}
}
static void
_filter_buffer_backing_free(Evas_Filter_Buffer *fb)
{
void *backing;
if (!fb) return;
if (fb->stolen)
{
fb->delete_me = EINA_TRUE;
return;
}
INF("Free backing of buffer %d fb @ %p backing @ %p alloc %d", fb->id, fb, fb->backing, fb->allocated);
backing = fb->backing;
fb->backing = NULL;
if (!fb->allocated) return;
fb->allocated = EINA_FALSE;
if (!backing) return;
if (!fb->ctx->gl_engine)
fb->ENFN->image_free(fb->ENDT, backing);
else
{
if (!evas_cserve2_use_get())
evas_cache_image_drop(backing);
else
evas_cache2_image_close(backing);
}
_backing_free(fb->ctx, backing);
}
/** @hidden private bind proxy to context */
@ -362,42 +373,111 @@ _rgba_image_alloc(Evas_Filter_Buffer const *fb, void *data)
return image;
}
/*
Eina_Bool
evas_filter_buffer_alloc(Evas_Filter_Buffer *fb, int w, int h)
{
if (!fb) return EINA_FALSE;
INF("Allocate buffer %d: backing %p", fb->id, fb->backing);
if (fb->backing)
{
RGBA_Image *im;
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;
if (!fb->transient)
{
ERR("Buffer dimensions mismatch with external image!");
//return EINA_FALSE;
// This needs to be counter-checked.
INF("Nope, gl engine is used");
return EINA_TRUE;
}
_filter_buffer_backing_free(fb);
im = fb->backing;
if (!im->image.data)
{
if (fb->allocated)
fb->ENFN->image_free(fb->ENDT, im);
fb->allocated = EINA_FALSE;
fb->backing = NULL;
}
else
{
fb->ENFN->image_size_get(fb->ENDT, fb->backing, &W, &H);
if ((W == w) && (H == h))
{
INF("Nope, already fine");
return EINA_TRUE;
}
if (!fb->transient)
ERR("Buffer dimensions mismatch with external image!");
_filter_buffer_backing_free(fb);
}
}
if ((fb->w && (fb->w != w)) || (fb->h && (fb->h != h)))
{
ERR("Buffer dimensions mismatch!");
//return EINA_FALSE;
}
if (fb->allocated) return EINA_TRUE;
if (fb->allocated && fb->backing)
{
RGBA_Image *a = fb->backing;
INF("Already allocated. Is that true? backing %p and data %p", a, a?a->image.data:NULL);
return EINA_TRUE;
}
fb->w = w;
fb->h = h;
fb->backing = _rgba_image_alloc(fb, NULL);
fb->allocated = (fb->backing != NULL);
RGBA_Image *a = fb->backing;
INF("Allocated buf %d with backing %p data %p", fb->id, fb->backing, a?a->image.data:0);
return fb->allocated;
}
*/
Eina_Bool
evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx, unsigned w, unsigned h)
{
Evas_Filter_Buffer *fb;
Image_Entry *ie;
Eina_List *li;
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
EINA_LIST_FOREACH(ctx->buffers, li, fb)
{
if (fb->source) continue;
ie = fb->backing;
if (ie)
{
if ((ie->w != w) || (ie->h != h))
{
CRI("Inconsistent buffer size!");
continue;
}
ie->references++;
continue;
}
if (!fb->w && !fb->h)
{
fb->w = w;
fb->h = h;
}
ie = (Image_Entry *) _rgba_image_alloc(fb, NULL);
if (!ie)
{
ERR("Buffer %d allocation failed!", fb->id);
continue;
}
fb->backing = ie;
}
// To unref: evas_unref_queue_image_put
return EINA_TRUE;
}
int
evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only)
@ -462,6 +542,7 @@ evas_filter_buffer_image_new(Evas_Filter_Context *ctx, RGBA_Image *image)
return fb->id;
}
/*
int
evas_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h,
Eina_Bool alpha_only)
@ -487,6 +568,7 @@ evas_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h,
return fb->id;
}
*/
static void
_buffer_free(Evas_Filter_Buffer *fb)
@ -525,16 +607,45 @@ evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
{
Evas_Filter_Buffer *buffer;
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
buffer = _filter_buffer_get(ctx, bufid);
if (!buffer) return NULL;
if (!buffer->glimage)
{
buffer->allocated = EINA_FALSE;
return buffer->backing;
}
else
buffer->stolen = EINA_TRUE;
if (buffer->glimage)
return buffer->glimage;
else
return buffer->backing;
}
Eina_Bool
evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer)
{
Image_Entry *ie = stolen_buffer;
Evas_Filter_Buffer *fb;
Eina_List *li;
if (!stolen_buffer) return EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
EINA_LIST_FOREACH(ctx->buffers, li, fb)
{
if (fb->backing == ie)
{
fb->stolen = EINA_FALSE;
if (fb->delete_me)
{
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
_buffer_free(fb);
return EINA_TRUE;
}
return EINA_TRUE;
}
}
_backing_free(ctx, ie);
return EINA_TRUE;
}
static Evas_Filter_Command *
@ -1418,29 +1529,12 @@ _filter_command_run(Evas_Filter_Command *cmd)
return EINA_TRUE;
}
if (!cmd->output->w && !cmd->output->h)
{
if (!cmd->output->backing)
{
cmd->output->w = cmd->ctx->w;
cmd->output->h = cmd->ctx->h;
}
}
if ((cmd->output->w <= 0) || (cmd->output->h <= 0))
{
ERR("Output size invalid: %dx%d", cmd->output->w, cmd->output->h);
return EINA_FALSE;
}
ok = evas_filter_buffer_alloc(cmd->output, cmd->output->w, cmd->output->h);
if (!ok)
{
ERR("Failed to allocate output buffer of size %dx%d",
cmd->output->w, cmd->output->h);
return EINA_FALSE;
}
//func = cmd->ENFN->filter_command_func_get(cmd);
// FIXME: Must call engine function, not CPU directly.

View File

@ -51,9 +51,6 @@ _filter_blend_cpu_alpha(Evas_Filter_Command *cmd)
if (!func)
return EINA_FALSE;
if (!evas_filter_buffer_alloc(cmd->output, cmd->output->w, cmd->output->h))
return EINA_FALSE;
in = cmd->input->backing;
out = cmd->output->backing;
sw = in->cache_entry.w;
@ -96,13 +93,12 @@ _filter_blend_cpu_rgba(Evas_Filter_Command *cmd)
RGBA_Draw_Context *drawctx;
int sw, sh, dx, dy, dw, dh, sx, sy;
if (!evas_filter_buffer_alloc(cmd->output, cmd->output->w, cmd->output->h))
return EINA_FALSE;
in = cmd->input->backing;
out = cmd->output->backing;
EINA_SAFETY_ON_NULL_RETURN_VAL(in, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(in->image.data, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(out->image.data, EINA_FALSE);
sx = 0;
sy = 0;
@ -324,9 +320,6 @@ _filter_blend_cpu_mask_rgba(Evas_Filter_Command *cmd)
DATA8 *maskdata;
int sw, sh, dw, dh, ox, oy, sx = 0, sy = 0, dx = 0, dy = 0, rows, cols, y;
if (!evas_filter_buffer_alloc(cmd->output, cmd->output->w, cmd->output->h))
return EINA_FALSE;
// TODO: Call _mapped_blend_cpu to implement repeat fill mode.
if (cmd->draw.fillmode != EVAS_FILTER_FILL_MODE_NONE)
ERR("Fill modes are not implemented for Alpha --> RGBA");
@ -343,6 +336,19 @@ _filter_blend_cpu_mask_rgba(Evas_Filter_Command *cmd)
maskdata = in->mask.data;
col = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
// TODO: Fix this crash. Change proxy image and OUTPUT data is NULL. Why?
if (!dstdata)
{
ERR("Empty destination from buffer #%d %dx%d %p", cmd->output->id, dw, dh, out);
//abort();
return EINA_FALSE;
}
if (!maskdata)
abort();
//EINA_SAFETY_ON_NULL_RETURN_VAL(dstdata, EINA_FALSE);
//EINA_SAFETY_ON_NULL_RETURN_VAL(maskdata, EINA_FALSE);
func = evas_common_gfx_func_composite_mask_color_span_get
(col, out, 1, cmd->draw.render_op);
@ -417,9 +423,6 @@ _filter_blend_cpu_rgba2alpha(Evas_Filter_Command *cmd)
RGBA_Image *in, *out;
int sw, sh, dx, dy, dw, dh, sx, sy;
if (!evas_filter_buffer_alloc(cmd->output, cmd->output->w, cmd->output->h))
return EINA_FALSE;
in = cmd->input->backing;
out = cmd->output->backing;
EINA_SAFETY_ON_NULL_RETURN_VAL(in, EINA_FALSE);
@ -439,6 +442,7 @@ _filter_blend_cpu_rgba2alpha(Evas_Filter_Command *cmd)
return EINA_TRUE;
// Stretch if necessary.
#warning FIXME Must be in the main loop because of buffer allocation
if ((sw != dw || sh != dh) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
{
Evas_Filter_Buffer *fb;

View File

@ -154,6 +154,8 @@ struct _Evas_Filter_Buffer
Eina_Bool allocated : 1; // allocated on demand, belongs to this context
Eina_Bool transient : 1; // temporary buffer (automatic allocation)
Eina_Bool locked : 1; // internal flag
Eina_Bool stolen : 1; // stolen by the client
Eina_Bool delete_me : 1; // request delete asap (after released by client)
};
enum _Evas_Filter_Interpolation_Mode

View File

@ -10,8 +10,8 @@ evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx,
int w, int h)
{
Evas_Filter_Buffer *fb;
void *dstdata = NULL;
void *srcdata;
Image_Entry *dstdata = NULL;
Image_Entry *srcdata;
void *drawctx;
srcdata = evas_filter_buffer_backing_get(ctx, src->id);
@ -20,11 +20,17 @@ evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx,
fb = evas_filter_temporary_buffer_get(ctx, w, h, src->alpha_only);
if (!fb) return NULL;
if (evas_filter_buffer_alloc(fb, w, h))
dstdata = evas_filter_buffer_backing_get(ctx, fb->id);
dstdata = evas_filter_buffer_backing_get(ctx, fb->id);
if (!dstdata)
{
ERR("Buffer allocation failed for size %dx%d", w, h);
CRI("No backing found for buffer %d", fb->id);
return NULL;
}
if ((dstdata->w != w) || (dstdata->h != h))
{
CRI("Buffer size mismatch: got %dx%d requested %dx%d",
dstdata->w, dstdata->h, w, h);
return NULL;
}

View File

@ -101,14 +101,18 @@ Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas);
void evas_filter_context_destroy(Evas_Filter_Context *ctx);
void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data);
#define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx)
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx, unsigned w, unsigned h);
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
int evas_filter_buffer_image_new(Evas_Filter_Context *ctx, RGBA_Image *image);
int evas_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h, Eina_Bool alpha_only);
//int evas_filter_buffer_data_new(Evas_Filter_Context *ctx, void *data, int w, int h, Eina_Bool alpha_only);
#define evas_filter_buffer_alloc_new(ctx, w, h, a) evas_filter_buffer_data_new(ctx, NULL, w, h, a)
void *evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid);
void *evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid);
Eina_Bool evas_filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data, int w, int h, Eina_Bool alpha_only);
Eina_Bool evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, void *stolen_buffer);
// Do not use
EINA_DEPRECATED Eina_Bool evas_filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data, int w, int h, Eina_Bool alpha_only);
Eina_Bool evas_filter_run(Evas_Filter_Context *ctx, Eina_Bool do_async);