forked from enlightenment/efl
evas filters: Cleanup unused buffers
This might not be used as over two consecutive runs all the same buffers should be used. But it could happen if some parameters in the filter change (eg. blur radius). Fixes major (GPU) memory leaks. Reuse mode is still leaking.
This commit is contained in:
parent
01a4ecd92c
commit
30ac315631
|
@ -65,7 +65,12 @@ struct _Evas_Filter_Post_Render_Data
|
|||
Eina_Bool success;
|
||||
};
|
||||
|
||||
static const Evas_Object_Filter_Data evas_filter_data_cow_default = {};
|
||||
// FIXME: This should be enabled (with proper heuristics)
|
||||
#define FILTER_CONTEXT_REUSE EINA_FALSE
|
||||
|
||||
static const Evas_Object_Filter_Data evas_filter_data_cow_default = {
|
||||
.reuse = FILTER_CONTEXT_REUSE
|
||||
};
|
||||
Eina_Cow *evas_object_filter_cow = NULL;
|
||||
|
||||
void
|
||||
|
@ -100,6 +105,7 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj,
|
|||
Eina_Bool destroy = !pd->data->reuse;
|
||||
Evas_Object_Filter_Data *fcow;
|
||||
Eo *eo_obj = obj->object;
|
||||
void *output = NULL;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
|
@ -110,36 +116,25 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj,
|
|||
}
|
||||
else
|
||||
{
|
||||
void *output = evas_filter_buffer_backing_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID, EINA_FALSE);
|
||||
|
||||
fcow = FCOW_BEGIN(pd);
|
||||
fcow->output = output;
|
||||
FCOW_END(fcow, pd);
|
||||
output = evas_filter_buffer_backing_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID, EINA_FALSE);
|
||||
FCOW_WRITE(pd, output, output);
|
||||
}
|
||||
|
||||
if (EINA_UNLIKELY(ctx != pd->data->context))
|
||||
{
|
||||
ERR("Filter context has changed! Destroying it now...");
|
||||
fcow = FCOW_BEGIN(pd);
|
||||
evas_filter_context_destroy(fcow->context);
|
||||
fcow->context = NULL;
|
||||
FCOW_END(fcow, pd);
|
||||
evas_filter_context_destroy(pd->data->context);
|
||||
destroy = EINA_TRUE;
|
||||
}
|
||||
|
||||
evas_filter_buffer_backing_release(ctx, previous);
|
||||
if (destroy)
|
||||
{
|
||||
evas_filter_buffer_backing_release(ctx, previous);
|
||||
evas_filter_context_destroy(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
if (pd->data->context != ctx)
|
||||
{
|
||||
fcow = FCOW_BEGIN(pd);
|
||||
fcow->context = ctx;
|
||||
FCOW_END(fcow, pd);
|
||||
}
|
||||
FCOW_WRITE(pd, context, ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -401,7 +396,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
|
|||
|
||||
if (filter)
|
||||
{
|
||||
ok = evas_filter_context_program_reuse(filter, pd->data->chain, X, Y);
|
||||
ok = evas_filter_context_program_use(filter, pd->data->chain, EINA_TRUE, X, Y);
|
||||
if (!ok)
|
||||
{
|
||||
fcow = FCOW_BEGIN(pd);
|
||||
|
|
|
@ -13002,6 +13002,7 @@ _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success)
|
|||
|
||||
if (filter->ti)
|
||||
{
|
||||
// FIXME: LEAK HERE!
|
||||
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;
|
||||
|
|
|
@ -155,8 +155,12 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
|||
void *old_surface;
|
||||
|
||||
old_surface = evas_ector_buffer_drawable_image_get(fb->buffer);
|
||||
if (old_surface && (old_surface != proxy_surface))
|
||||
_filter_buffer_backing_free(fb);
|
||||
if (old_surface)
|
||||
{
|
||||
evas_ector_buffer_engine_image_release(fb->buffer, old_surface);
|
||||
if (old_surface && (old_surface != proxy_surface))
|
||||
_filter_buffer_backing_free(fb);
|
||||
}
|
||||
}
|
||||
XDBG("Source #%d '%s' has dimensions %dx%d", fb->id, fb->source_name, fb->w, fb->h);
|
||||
if (!fb->buffer) fb->buffer = ENFN->ector_buffer_wrap(ENDT, obj->layer->evas->evas, source->proxy->surface);
|
||||
|
@ -164,15 +168,12 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
|
|||
}
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, int x, int y)
|
||||
void
|
||||
_evas_filter_context_program_reuse(Evas_Filter_Context *ctx)
|
||||
{
|
||||
Evas_Filter_Buffer *fb;
|
||||
Eina_List *li;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
|
||||
|
||||
_filter_buffer_unlock_all(ctx);
|
||||
|
||||
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
||||
|
@ -194,9 +195,9 @@ evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program
|
|||
ENFN->rectangle_draw(ENDT, dc, surface, 0, 0, fb->w, fb->h, ctx->async);
|
||||
ENFN->context_free(ENDT, dc);
|
||||
fb->dirty = EINA_FALSE;
|
||||
}
|
||||
|
||||
return evas_filter_context_program_use(ctx, pgm, EINA_TRUE, x, y);
|
||||
evas_ector_buffer_engine_image_release(fb->buffer, surface);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -268,29 +269,34 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
|
|||
{
|
||||
Evas_Filter_Command *cmd;
|
||||
Evas_Filter_Buffer *fb;
|
||||
Eina_List *li;
|
||||
Eina_List *li, *li2;
|
||||
unsigned w, h;
|
||||
|
||||
if (ctx->run_count > 0) return EINA_TRUE;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
|
||||
w = ctx->w;
|
||||
h = ctx->h;
|
||||
|
||||
XDBG("Allocating all buffers based on output size %ux%u", w, h);
|
||||
|
||||
EINA_LIST_FOREACH(ctx->buffers, li, fb)
|
||||
fb->cleanup = EINA_TRUE;
|
||||
|
||||
EINA_INLIST_FOREACH(ctx->commands, cmd)
|
||||
{
|
||||
Evas_Filter_Fill_Mode fillmode = cmd->draw.fillmode;
|
||||
Evas_Filter_Buffer *in, *out;
|
||||
|
||||
in = cmd->input;
|
||||
in->cleanup = EINA_FALSE;
|
||||
if (!in->w && !in->h)
|
||||
{
|
||||
in->w = w;
|
||||
in->h = h;
|
||||
}
|
||||
|
||||
if (cmd->mask)
|
||||
cmd->mask->cleanup = EINA_FALSE;
|
||||
|
||||
// FIXME: No need for stretch buffers with GL!
|
||||
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY)
|
||||
{
|
||||
|
@ -326,6 +332,7 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
|
|||
fb ? fb->id : -1, sw, sh, in->alpha_only ? "alpha" : "rgba");
|
||||
if (!fb) goto alloc_fail;
|
||||
fb->transient = EINA_TRUE;
|
||||
fb->cleanup = EINA_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,9 +349,11 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
|
|||
fb ? fb->id : -1, sw, sh, in->alpha_only ? "alpha" : "rgba");
|
||||
if (!fb) goto alloc_fail;
|
||||
fb->transient = EINA_TRUE;
|
||||
fb->cleanup = EINA_FALSE;
|
||||
}
|
||||
|
||||
out = cmd->output;
|
||||
out->cleanup = EINA_FALSE;
|
||||
if (!out->w && !out->h)
|
||||
{
|
||||
out->w = w;
|
||||
|
@ -356,7 +365,12 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
|
|||
{
|
||||
Eina_Bool render = EINA_FALSE, draw = EINA_FALSE;
|
||||
|
||||
if (fb->buffer || fb->source)
|
||||
if (fb->source)
|
||||
{
|
||||
fb->cleanup = EINA_FALSE;
|
||||
continue;
|
||||
}
|
||||
if (fb->buffer || fb->cleanup)
|
||||
continue;
|
||||
|
||||
if (!fb->w && !fb->h)
|
||||
|
@ -378,6 +392,16 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
|
|||
if (!fb->buffer) goto alloc_fail;
|
||||
}
|
||||
|
||||
EINA_LIST_FOREACH_SAFE(ctx->buffers, li, li2, fb)
|
||||
{
|
||||
if (fb->cleanup)
|
||||
{
|
||||
XDBG("Cleanup buffer #%d %dx%d %s", fb->id, fb->w, fb->h, fb->alpha_only ? "alpha" : "rgba");
|
||||
ctx->buffers = eina_list_remove_list(ctx->buffers, li);
|
||||
_buffer_free(fb);
|
||||
}
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
alloc_fail:
|
||||
|
@ -527,25 +551,30 @@ evas_filter_buffer_backing_set(Evas_Filter_Context *ctx, int bufid,
|
|||
void *engine_buffer)
|
||||
{
|
||||
Evas_Filter_Buffer *fb;
|
||||
Eina_Bool ret = EINA_FALSE;
|
||||
Eo *buffer = NULL;
|
||||
|
||||
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);
|
||||
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;
|
||||
ret = buffer ? EINA_TRUE : EINA_FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (fb->buffer) return EINA_FALSE;
|
||||
if (fb->is_render) return EINA_FALSE;
|
||||
if (fb->is_render) goto end;
|
||||
|
||||
fb->buffer = ENFN->ector_buffer_wrap(ENDT, ctx->evas->evas, engine_buffer);
|
||||
return EINA_TRUE;
|
||||
buffer = ENFN->ector_buffer_wrap(ENDT, ctx->evas->evas, engine_buffer);
|
||||
ret = EINA_TRUE;
|
||||
|
||||
end:
|
||||
if (fb->buffer != buffer) efl_unref(fb->buffer);
|
||||
fb->buffer = buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
|
|
|
@ -3486,6 +3486,8 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
|
|||
|
||||
XDBG("Using program '%s' for context %p", pgm->name, ctx);
|
||||
|
||||
if (reuse) _evas_filter_context_program_reuse(ctx);
|
||||
|
||||
// Copy current state (size, edje state val, color class, etc...)
|
||||
ctx->w = pgm->state.w;
|
||||
ctx->h = pgm->state.h;
|
||||
|
|
|
@ -265,6 +265,7 @@ struct _Evas_Filter_Buffer
|
|||
Eina_Bool locked : 1; // internal flag
|
||||
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)
|
||||
Eina_Bool cleanup : 1; // Needs cleaning up if not allocated
|
||||
};
|
||||
|
||||
enum _Evas_Filter_Interpolation_Mode
|
||||
|
@ -295,6 +296,7 @@ Evas_Filter_Buffer *evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx, Evas
|
|||
Eina_Bool evas_filter_interpolate(DATA8* output /* 256 values */, int *points /* 256 values */, Evas_Filter_Interpolation_Mode mode);
|
||||
int evas_filter_smallest_pow2_larger_than(int val);
|
||||
|
||||
void _evas_filter_context_program_reuse(Evas_Filter_Context *ctx);
|
||||
void evas_filter_parser_shutdown(void);
|
||||
|
||||
#define E_READ ECTOR_BUFFER_ACCESS_FLAG_READ
|
||||
|
|
|
@ -148,7 +148,6 @@ Eina_Bool evas_filter_context_async_get(Evas_Filter_Context *ctx)
|
|||
void evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *H);
|
||||
void evas_filter_context_destroy(Evas_Filter_Context *ctx);
|
||||
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse, int object_x, int object_y);
|
||||
Eina_Bool evas_filter_context_program_reuse(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, int x, int y);
|
||||
void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async);
|
||||
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)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#define ECTOR_GL_BUFFER_BASE_PROTECTED
|
||||
|
||||
#include "evas_common_private.h"
|
||||
#include "evas_gl_private.h"
|
||||
|
||||
#include <gl/Ector_GL.h>
|
||||
#include "gl/ector_gl_private.h"
|
||||
|
@ -17,6 +16,7 @@
|
|||
|
||||
#include "evas_ector_buffer.eo.h"
|
||||
#include "evas_ector_gl_buffer.eo.h"
|
||||
#include "evas_gl_private.h"
|
||||
|
||||
#define MY_CLASS EVAS_ECTOR_GL_BUFFER_CLASS
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#define ECTOR_GL_BUFFER_BASE_PROTECTED
|
||||
|
||||
#include "evas_common_private.h"
|
||||
#include "evas_gl_private.h"
|
||||
|
||||
#include <gl/Ector_GL.h>
|
||||
#include "gl/ector_gl_private.h"
|
||||
|
@ -20,6 +19,7 @@
|
|||
#include "evas_ector_buffer.eo.h"
|
||||
#include "evas_ector_gl_buffer.eo.h"
|
||||
#include "evas_ector_gl_image_buffer.eo.h"
|
||||
#include "evas_gl_private.h"
|
||||
|
||||
#define MY_CLASS EVAS_ECTOR_GL_IMAGE_BUFFER_CLASS
|
||||
|
||||
|
|
Loading…
Reference in New Issue