evas filters: Fix blur logic and GL buffer handling

This corrects two things:
- the blur filter high-level logic, that lead to reusing some
  temporary buffers which contained garbage;
- the versatile gl buffer implementation so that it now properly
  switches between the RGBA_Image and the FBO content (yes, this
  is insanely slow and inefficient... but it works and that was
  the only point).
This commit is contained in:
Jean-Philippe Andre 2017-01-23 17:55:17 +09:00
parent 2ef8d6f39a
commit 92dfe1831c
16 changed files with 398 additions and 178 deletions

View File

@ -341,7 +341,6 @@ evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only)
fb = _buffer_empty_new(ctx, 0, 0, alpha_only, EINA_FALSE);
if (!fb) return -1;
XDBG("Created context buffer %d %s", fb->id, alpha_only ? "alpha" : "rgba");
return fb->id;
}
@ -403,7 +402,7 @@ evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return NULL;
return evas_ector_buffer_drawable_image_get(fb->buffer, EINA_TRUE);
return evas_ector_buffer_drawable_image_get(fb->buffer);
}
Eina_Bool
@ -434,6 +433,7 @@ _command_new(Evas_Filter_Context *ctx, Evas_Filter_Mode mode,
cmd->input = input;
cmd->mask = mask;
cmd->output = output;
if (output) output->dirty = EINA_TRUE;
ctx->commands = eina_inlist_append(ctx->commands, EINA_INLIST_GET(cmd));
return cmd;
@ -454,19 +454,20 @@ _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd)
Evas_Filter_Buffer *
evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h,
Eina_Bool alpha_only)
Eina_Bool alpha_only, Eina_Bool clean)
{
Evas_Filter_Buffer *buf = NULL;
Evas_Filter_Buffer *fb = NULL;
Eina_List *l;
EINA_LIST_FOREACH(ctx->buffers, l, buf)
EINA_LIST_FOREACH(ctx->buffers, l, fb)
{
if (buf->transient && !buf->locked && (buf->alpha_only == alpha_only))
if (fb->transient && !fb->locked && (fb->alpha_only == alpha_only)
&& (!clean || !fb->dirty))
{
if ((!w || (w == buf->w)) && (!h || (h == buf->h)))
if ((!w || (w == fb->w)) && (!h || (h == fb->h)))
{
buf->locked = EINA_TRUE;
return buf;
fb->locked = EINA_TRUE;
return fb;
}
}
}
@ -477,10 +478,11 @@ evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h,
return NULL;
}
buf = _buffer_empty_new(ctx, w, h, alpha_only, EINA_TRUE);
buf->locked = EINA_TRUE;
fb = _buffer_empty_new(ctx, w, h, alpha_only, EINA_TRUE);
fb->locked = EINA_TRUE;
XDBG("Created temporary buffer %d %s", fb->id, alpha_only ? "alpha" : "rgba");
return buf;
return fb;
}
static void
@ -522,7 +524,9 @@ evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context,
XDBG("Add fill %d with color(%d,%d,%d,%d)", buf->id, R, G, B, A);
buf->dirty = EINA_TRUE;
if (!R && !G && !B && !A)
buf->dirty = EINA_FALSE;
return cmd;
}
@ -533,10 +537,16 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
{
Evas_Filter_Buffer *in = NULL, *out = NULL, *tmp = NULL, *in_dy = NULL;
Evas_Filter_Buffer *out_dy = NULL, *out_dx = NULL;
Evas_Filter_Buffer *copybuf = NULL, *blur_out = NULL;
Eina_Bool copy_back = EINA_FALSE, blend = EINA_FALSE;
Evas_Filter_Buffer *copybuf = NULL, *blendbuf = NULL;
Evas_Filter_Command *cmd = NULL;
int R, G, B, A; DATA32 color;
int R, G, B, A, render_op;
Eina_Bool override;
DATA32 color;
// Note (SW engine):
// The basic blur operation overrides the pixels in the target buffer,
// only supports one direction (X or Y) and no offset. As a consequence
// most cases require intermediate work buffers.
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, NULL);
@ -555,20 +565,19 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
out = _filter_buffer_get(ctx, outbuf);
EINA_SAFETY_ON_FALSE_GOTO(out, fail);
if (!in->alpha_only && out->alpha_only)
DBG("Different color formats, implicit conversion may be slow");
if (in == out) out->dirty = EINA_FALSE;
blend = (out->dirty && !out->transient);
ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A);
color = ARGB_JOIN(A, R, G, B);
if (!color)
{
DBG("Blur with transparent color. Nothing to do.");
/* FIXME: return skip; */
return _command_new(ctx, EVAS_FILTER_MODE_SKIP, NULL, NULL, NULL);
}
render_op = ENFN->context_render_op_get(ENDT, drawctx);
override = (render_op == EVAS_RENDER_COPY);
switch (type)
{
case EVAS_FILTER_BLUR_GAUSSIAN:
@ -580,48 +589,47 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
break;
case EVAS_FILTER_BLUR_DEFAULT:
/* In DEFAULT mode we cheat, depending on the size of the kernel:
* For 1px to 2px, use true Gaussian blur.
* For 3px to 6px, use two Box blurs.
* For more than 6px, use three Box blurs.
* This will give both nicer and MUCH faster results than Gaussian.
*
* NOTE: When implementing blur with GL shaders, other tricks will be
* needed, of course!
*/
{
const Eina_Bool alpha = in->alpha_only;
/* In DEFAULT mode we cheat, depending on the size of the kernel:
* For 1px to 2px, use true Gaussian blur.
* For 3px to 6px, use two Box blurs.
* For more than 6px, use three Box blurs.
* This will give both nicer and MUCH faster results than Gaussian.
*
* NOTE: This step should be avoided in GL.
*/
int tmp_out = outbuf;
int tmp_in = inbuf;
int tmp_ox = ox;
int tmp_oy = oy;
// For 2D blur: create intermediate buffer
if (dx && dy)
{
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, alpha);
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 1);
if (!tmp) goto fail;
tmp_in = tmp_out = tmp->id;
tmp_ox = tmp_oy = 0;
}
// X box blur
if (dx)
{
if (dx <= 2)
type = EVAS_FILTER_BLUR_GAUSSIAN;
else
type = EVAS_FILTER_BLUR_BOX;
type = EVAS_FILTER_BLUR_BOX;
if (dy && (color != 0xFFFFFFFF))
ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
if (dy) ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
cmd = evas_filter_command_blur_add(ctx, drawctx, inbuf, tmp_out,
type, dx, 0, tmp_ox, tmp_oy, 0);
if (!cmd) goto fail;
cmd->blur.auto_count = EINA_TRUE;
if (dy && (color != 0xFFFFFFFF))
ENFN->context_color_set(ENDT, drawctx, R, G, B, A);
if (dy) ENFN->context_color_set(ENDT, drawctx, R, G, B, A);
}
// Y box blur
if (dy)
{
if (dy <= 2)
@ -629,51 +637,39 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
else
type = EVAS_FILTER_BLUR_BOX;
if (dx && (inbuf == outbuf))
ENFN->context_render_op_set(ENDT, drawctx, EVAS_RENDER_COPY);
cmd = evas_filter_command_blur_add(ctx, drawctx, tmp_in, outbuf,
type, 0, dy, ox, oy, 0);
if (dx && (inbuf == outbuf))
ENFN->context_render_op_set(ENDT, drawctx, render_op);
if (!cmd) goto fail;
cmd->blur.auto_count = EINA_TRUE;
}
return cmd;
}
break;
default:
CRI("Not implemented yet!");
goto fail;
}
if ((blend || (in->alpha_only && !out->alpha_only)) ||
(!blend && !in->alpha_only && !out->alpha_only && (color != 0xFFFFFFFF)) ||
(!in->alpha_only && out->alpha_only))
{
XDBG("Adding extra blending step %d --> %d (%s --> %s)", in->id, out->id,
in->alpha_only ? "Alpha" : "RGBA",
out->alpha_only ? "Alpha" : "RGBA");
Eina_Bool wasl = in->locked;
in->locked = 1;
blur_out = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
in->locked = wasl;
if (!blur_out) goto fail;
blend = EINA_TRUE;
}
else
blur_out = out;
// For 2D blur: create intermediate buffer between X and Y passes
if (dx && dy)
{
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
if (!tmp) goto fail;
if (!blend && (ox || oy))
// If there's an offset: create intermediate buffer before offset blend
if (ox || oy)
{
copybuf = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
copybuf = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!copybuf) goto fail;
copy_back = EINA_TRUE;
}
if (in == blur_out)
// Intermediate buffer between X and Y passes
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
if (in == out)
{
// IN = OUT and 2-D blur. IN -blur-> TMP -blur-> IN.
out_dx = tmp;
@ -685,43 +681,80 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
// IN != OUT and 2-D blur. IN -blur-> TMP -blur-> OUT.
out_dx = tmp;
in_dy = tmp;
out_dy = copybuf ? copybuf : blur_out;
out_dy = copybuf ? copybuf : out;
}
}
else if (dx)
{
if ((in == blur_out) || ox || oy)
// X blur only
if (in == out)
{
// IN = OUT and 1-D blur. IN -blur-> TMP -copy-> IN.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
copy_back = EINA_TRUE;
copybuf = tmp;
out_dx = tmp;
}
else if (ox || oy || (color != 0xFFFFFFFF))
{
// IN != OUT and 1-D blur. IN -blur-> TMP -blend-> OUT.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
blendbuf = tmp;
out_dx = tmp;
}
else if (out->dirty)
{
// IN != OUT and 1-D blur. IN -blur-> TMP -blend-> OUT.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
blendbuf = tmp;
out_dx = tmp;
}
else
{
// IN != OUT and 1-D blur. IN -blur-> OUT.
out_dx = blur_out;
out_dx = out;
}
}
else
{
if ((in == blur_out) || ox || oy)
// Y blur only
if (in == out)
{
// IN = OUT and 1-D blur. IN -blur-> TMP -copy-> IN.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only);
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
copy_back = EINA_TRUE;
copybuf = tmp;
in_dy = in;
out_dy = tmp;
}
else if (ox || oy || (color != 0xFFFFFFFF))
{
// IN != OUT and 1-D blur. IN -blur-> TMP -blend-> IN.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
if (override)
copybuf = tmp;
else
blendbuf = tmp;
in_dy = in;
out_dy = tmp;
}
else if (out->dirty && !override)
{
// IN != OUT and 1-D blur. IN -blur-> TMP -blend-> OUT.
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 0);
if (!tmp) goto fail;
blendbuf = tmp;
in_dy = in;
out_dy = tmp;
}
else
{
// IN != OUT and 1-D blur. IN -blur-> OUT.
in_dy = in;
out_dy = blur_out;
out_dy = out;
}
}
@ -734,8 +767,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
cmd->blur.dx = dx;
cmd->blur.dy = 0;
cmd->blur.count = count;
if (!dy && !blend)
DRAW_COLOR_SET(R, G, B, A);
if (!dy) DRAW_COLOR_SET(R, G, B, A);
}
if (dy)
@ -747,38 +779,36 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
cmd->blur.dx = 0;
cmd->blur.dy = dy;
cmd->blur.count = count;
if (!blend)
DRAW_COLOR_SET(R, G, B, A);
DRAW_COLOR_SET(R, G, B, A);
}
if (copy_back)
if (blendbuf)
{
Evas_Filter_Command *blendcmd;
XDBG("Add extra blend %d -> %d", blendbuf->id, out->id);
blendcmd = evas_filter_command_blend_add(ctx, drawctx,
blendbuf->id, out->id, ox, oy,
EVAS_FILTER_FILL_MODE_NONE);
if (!blendcmd) goto fail;
ox = oy = 0;
}
else if (copybuf)
{
Evas_Filter_Command *copycmd;
int render_op;
if (!cmd) goto fail;
XDBG("Add copy %d -> %d", copybuf->id, blur_out->id);
XDBG("Add extra copy %d -> %d: offset: %d,%d", copybuf->id, out->id, ox, oy);
ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
render_op = ENFN->context_render_op_get(ENDT, drawctx);
ENFN->context_render_op_set(ENDT, drawctx, EVAS_RENDER_COPY);
copycmd = evas_filter_command_blend_add(ctx, drawctx, copybuf->id, blur_out->id, ox, oy, EVAS_FILTER_FILL_MODE_NONE);
copycmd = evas_filter_command_blend_add(ctx, drawctx,
copybuf->id, out->id, ox, oy,
EVAS_FILTER_FILL_MODE_NONE);
ENFN->context_color_set(ENDT, drawctx, R, G, B, A);
ENFN->context_render_op_set(ENDT, drawctx, render_op);
if (!copycmd) goto fail;
ox = oy = 0;
}
if (blend)
{
Evas_Filter_Command *blendcmd;
XDBG("Add blend %d (%s) -> %d (%s)",
blur_out->id, blur_out->alpha_only ? "Alpha" : "RGBA",
out->id, out->alpha_only ? "Alpha" : "RGBA");
blendcmd = evas_filter_command_blend_add(ctx, drawctx, blur_out->id, out->id, ox, oy, EVAS_FILTER_FILL_MODE_NONE);
if (!blendcmd) goto fail;
}
out->dirty = EINA_TRUE;
_filter_buffer_unlock_all(ctx);
return cmd;
@ -796,6 +826,7 @@ evas_filter_command_blend_add(Evas_Filter_Context *ctx, void *drawctx,
{
Evas_Filter_Command *cmd;
Evas_Filter_Buffer *in, *out;
Eina_Bool copy;
int R, G, B, A;
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
@ -823,18 +854,24 @@ evas_filter_command_blend_add(Evas_Filter_Context *ctx, void *drawctx,
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, in, NULL, out);
if (!cmd) return NULL;
if (ENFN->context_render_op_get(ENDT, drawctx) == EVAS_RENDER_COPY)
copy = EINA_TRUE;
else
copy = EINA_FALSE;
ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A);
DRAW_COLOR_SET(R, G, B, A);
DRAW_FILL_SET(fillmode);
cmd->draw.ox = ox;
cmd->draw.oy = oy;
cmd->draw.rop = _evas_to_gfx_render_op(ENFN->context_render_op_get(ENDT, drawctx));
cmd->draw.rop = copy ? EFL_GFX_RENDER_OP_COPY : EFL_GFX_RENDER_OP_BLEND;
cmd->draw.clip_use =
ENFN->context_clip_get(ENDT, drawctx,
&cmd->draw.clip.x, &cmd->draw.clip.y,
&cmd->draw.clip.w, &cmd->draw.clip.h);
XDBG("Add blend %d -> %d", in->id, out->id);
XDBG("Add %s %d -> %d: offset %d,%d, color: %d,%d,%d,%d",
copy ? "copy" : "blend", in->id, out->id, ox, oy, R, G, B, A);
if (cmd->draw.clip_use)
XDBG("Draw clip: %d,%d,%d,%d", cmd->draw.clip.x, cmd->draw.clip.y,
cmd->draw.clip.w, cmd->draw.clip.h);
@ -864,9 +901,12 @@ evas_filter_command_grow_add(Evas_Filter_Context *ctx, void *draw_context,
in = _filter_buffer_get(ctx, inbuf);
EINA_SAFETY_ON_NULL_RETURN_VAL(in, NULL);
if (inbuf != outbuf)
out = _filter_buffer_get(ctx, outbuf);
EINA_SAFETY_ON_NULL_RETURN_VAL(out, NULL);
if ((inbuf != outbuf) && out->dirty)
{
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only);
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only, 1);
EINA_SAFETY_ON_NULL_RETURN_VAL(tmp, NULL);
growbuf = tmp->id;
}
@ -901,16 +941,6 @@ evas_filter_command_grow_add(Evas_Filter_Context *ctx, void *draw_context,
memset(curve + end, 255, 256 - end);
}
out = _filter_buffer_get(ctx, growbuf);
if (!out) return NULL;
out->dirty = EINA_TRUE;
if (growbuf != outbuf)
{
out = _filter_buffer_get(ctx, growbuf);
if (!out) return NULL;
out->dirty = EINA_TRUE;
}
threshcmd = evas_filter_command_curve_add(ctx, draw_context, growbuf, growbuf,
curve, EVAS_FILTER_CHANNEL_ALPHA);
if (!threshcmd)
@ -973,7 +1003,6 @@ evas_filter_command_curve_add(Evas_Filter_Context *ctx,
cmd->curve.data = copy;
cmd->curve.channel = channel;
out->dirty = EINA_TRUE;
return cmd;
}
@ -1009,7 +1038,7 @@ evas_filter_command_displacement_map_add(Evas_Filter_Context *ctx,
if (in == out)
{
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only);
tmp = evas_filter_temporary_buffer_get(ctx, in->w, in->h, in->alpha_only, 1);
if (!tmp) return NULL;
disp_out = tmp;
}
@ -1033,8 +1062,6 @@ evas_filter_command_displacement_map_add(Evas_Filter_Context *ctx,
if (!fillcmd) goto fail;
}
out->dirty = EINA_TRUE;
_filter_buffer_unlock_all(ctx);
return cmd;
@ -1072,7 +1099,6 @@ evas_filter_command_mask_add(Evas_Filter_Context *ctx, void *draw_context,
cmd->draw.rop = render_op;
DRAW_COLOR_SET(R, G, B, A);
DRAW_FILL_SET(fillmode);
out->dirty = EINA_TRUE;
return cmd;
}
@ -1122,7 +1148,6 @@ evas_filter_command_bump_map_add(Evas_Filter_Context *ctx,
cmd->bump.white = white;
cmd->bump.elevation = elevation;
cmd->bump.compensate = !!(flags & EVAS_FILTER_BUMP_COMPENSATE);
out->dirty = EINA_TRUE;
return cmd;
}
@ -1160,8 +1185,6 @@ evas_filter_command_transform_add(Evas_Filter_Context *ctx,
else
cmd->draw.rop = EFL_GFX_RENDER_OP_BLEND;
out->dirty = EINA_TRUE;
return cmd;
}
@ -1211,7 +1234,7 @@ _filter_target_render(Evas_Filter_Context *ctx)
src = _filter_buffer_get(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
image = evas_ector_buffer_drawable_image_get(src->buffer, EINA_FALSE);
image = evas_ector_buffer_drawable_image_get(src->buffer);
EINA_SAFETY_ON_NULL_GOTO(image, fail);
// FIXME: Use ector buffer RENDERER here
@ -1272,7 +1295,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, EINA_FALSE);
surface = evas_ector_buffer_render_image_get(fb->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
// Copied from evas_font_draw_async_check
@ -1306,7 +1329,7 @@ evas_filter_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
fb = _filter_buffer_get(ctx, bufid);
if (!fb) return EINA_FALSE;
surface = evas_ector_buffer_render_image_get(fb->buffer, 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);
@ -1391,6 +1414,7 @@ _filter_name_get(int mode)
#define FNAME(a) case EVAS_FILTER_MODE_ ## a: return "EVAS_FILTER_MODE_" #a
switch (mode)
{
FNAME(SKIP);
FNAME(BLEND);
FNAME(BLUR);
FNAME(CURVE);
@ -1409,6 +1433,9 @@ _filter_command_run(Evas_Filter_Command *cmd)
{
Evas_Filter_Support support = EVAS_FILTER_SUPPORT_NONE;
if (cmd->mode == EVAS_FILTER_MODE_SKIP)
return EINA_TRUE;
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, EINA_FALSE);

View File

@ -2861,6 +2861,8 @@ _buffers_update(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm)
pgm->changed = EINA_TRUE;
buf->w = fb->w = source->cur->geometry.w;
buf->h = fb->h = source->cur->geometry.h;
XDBG("Created proxy buffer %d %s '%s'", fb->id,
buf->alpha ? "alpha" : "rgba", buf->name);
}
else
{
@ -2870,6 +2872,8 @@ _buffers_update(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm)
fb = _filter_buffer_get(ctx, buf->cid);
fb->w = buf->w = pgm->state.w;
fb->h = buf->h = pgm->state.h;
XDBG("Created context buffer %d %s '%s'", fb->id,
buf->alpha ? "alpha" : "rgba", buf->name);
}
}
}

View File

@ -266,7 +266,7 @@ void evas_filter_context_source_set(Evas_Filter_Context *ctx
void _clip_to_target(int *sx, int *sy, int sw, int sh, int ox, int oy, int dw, int dh, int *dx, int *dy, int *rows, int *cols);
Eina_Bool evas_filter_buffer_alloc(Evas_Filter_Buffer *fb, int w, int h);
Evas_Filter_Buffer *_filter_buffer_get(Evas_Filter_Context *ctx, int bufid);
Evas_Filter_Buffer *evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only);
Evas_Filter_Buffer *evas_filter_temporary_buffer_get(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only, Eina_Bool clean);
Evas_Filter_Buffer *evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h);
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);

View File

@ -19,7 +19,7 @@ evas_filter_buffer_scaled_get(Evas_Filter_Context *ctx,
DEBUG_TIME_BEGIN();
// Get destination buffer
dst = evas_filter_temporary_buffer_get(ctx, w, h, src->alpha_only);
dst = evas_filter_temporary_buffer_get(ctx, w, h, src->alpha_only, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, NULL);
// Map input and output

View File

@ -19,16 +19,10 @@ interface Evas.Ector.Buffer
}
drawable_image_get {
[[Fetch an engine image from this ector buffer as a drawable.]]
params {
@in update: bool; [[$true to update the data to the remote image.]]
}
return: void_ptr; [[The engine image (RGBA_Image or Evas_GL_Image).]]
}
render_image_get {
[[Fetch an engine image from this ector buffer as a render target.]]
params {
@in update: bool; [[$true to update the data to the remote image.]]
}
return: void_ptr; [[The engine image (RGBA_Image or Evas_GL_Image).]]
}
engine_image_release {

View File

@ -55,6 +55,7 @@ typedef void (* Evas_Filter_Cb) (Evas_Filter_Context *ctx, void *data, Eina_Bool
/** @internal */
enum _Evas_Filter_Mode
{
EVAS_FILTER_MODE_SKIP, /**< No operation */
EVAS_FILTER_MODE_BLEND, /**< Blend with current context render_op */
EVAS_FILTER_MODE_BLUR, /**< @see Evas_Filter_Blur_Type */
EVAS_FILTER_MODE_CURVE, /**< Apply color curve */

View File

@ -689,6 +689,7 @@ void evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_G
void evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int npoints, RGBA_Map_Point *p, int smooth, int level);
void evas_gl_common_image_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int smooth);
Evas_GL_Image *evas_gl_common_image_surface_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im);
Evas_GL_Image *evas_gl_common_image_surface_detach(Evas_Engine_GL_Context *gc, Evas_GL_Image *im);
void *evas_gl_font_texture_new(void *gc, RGBA_Font_Glyph *fg);
void evas_gl_font_texture_free(void *);

View File

@ -1100,6 +1100,17 @@ fail:
return NULL;
}
Evas_GL_Image *
evas_gl_common_image_surface_detach(Evas_Engine_GL_Context *gc EINA_UNUSED, Evas_GL_Image *im)
{
if (!im || !im->im) return im;
evas_cache_image_drop(&im->im->cache_entry);
im->im = NULL;
return im;
}
void
evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
int npoints, RGBA_Map_Point *p, int smooth, int level EINA_UNUSED)

View File

@ -23,6 +23,8 @@
typedef struct _Ector_GL_Buffer_Map Ector_GL_Buffer_Map;
typedef struct _Evas_Ector_GL_Buffer_Data Evas_Ector_GL_Buffer_Data;
static int _map_id = 0;
struct _Ector_GL_Buffer_Map
{
EINA_INLIST;
@ -30,6 +32,7 @@ struct _Ector_GL_Buffer_Map
unsigned int base_size; // in bytes
unsigned int x, y, w, h;
void *image_data, *base_data;
int map_id;
size_t length;
Efl_Gfx_Colorspace cspace;
Evas_GL_Image *im;
@ -41,7 +44,7 @@ struct _Evas_Ector_GL_Buffer_Data
{
Evas_Public_Data *evas;
Evas_GL_Image *glim;
Eina_Bool alpha_only;
Eina_Bool alpha_only, was_render;
Ector_GL_Buffer_Map *maps;
};
@ -55,6 +58,20 @@ struct _Evas_Ector_GL_Buffer_Data
#define fail(fmt, ...) do { ERR(fmt, ##__VA_ARGS__); goto on_fail; } while (0)
#if 0
static inline void
_mapped_image_dump(Eo *buf, Evas_GL_Image *im, const char *fmt, int id)
{
if (!im || !im->im) return;
evas_common_save_image_to_file(im->im, eina_slstr_printf("/tmp/dump/%s_%02d_buf_%p_im_%p.png", fmt, id, buf, im),
NULL, 100, 9, NULL);
}
#define MAP_DUMP(_im, _fmt) _mapped_image_dump(obj, _im, _fmt, map->map_id)
#else
#define MAP_DUMP(...)
#endif
/* FIXME: Conversion routines don't belong here */
static inline void
_pixels_argb_to_gry8_convert(uint8_t *dst, const uint32_t *src, int len)
@ -120,23 +137,14 @@ on_fail:
pd->glim = NULL;
}
EOLIAN static void *
_evas_ector_gl_buffer_evas_ector_buffer_drawable_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_GL_Buffer_Data *pd,
Eina_Bool update)
static inline void *
_image_get(Evas_Ector_GL_Buffer_Data *pd, Eina_Bool render)
{
Render_Engine_GL_Generic *re = pd->evas->engine.data.output;
Evas_Engine_GL_Context *gc;
if (pd->maps != NULL)
fail("Image is currently mapped!");
evas_gl_common_image_ref(pd->glim);
if (!update) return pd->glim;
gc = re->window_gl_context_get(re->software.ob);
evas_gl_common_image_update(gc, pd->glim);
if (render) pd->was_render = EINA_TRUE;
return pd->glim;
on_fail:
@ -144,26 +152,17 @@ on_fail:
}
EOLIAN static void *
_evas_ector_gl_buffer_evas_ector_buffer_render_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_GL_Buffer_Data *pd,
Eina_Bool update)
_evas_ector_gl_buffer_evas_ector_buffer_drawable_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_GL_Buffer_Data *pd)
{
Render_Engine_GL_Generic *re = pd->evas->engine.data.output;
Evas_Engine_GL_Context *gc;
return _image_get(pd, EINA_FALSE);
}
if (pd->maps != NULL)
fail("Image is currently mapped!");
evas_gl_common_image_ref(pd->glim);
if (!update) return pd->glim;
gc = re->window_gl_context_get(re->software.ob);
evas_gl_common_image_update(gc, pd->glim);
return pd->glim;
on_fail:
return NULL;
EOLIAN static void *
_evas_ector_gl_buffer_evas_ector_buffer_render_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_GL_Buffer_Data *pd)
{
return _image_get(pd, EINA_TRUE);
}
EOLIAN static Eina_Bool
@ -174,6 +173,14 @@ _evas_ector_gl_buffer_evas_ector_buffer_engine_image_release(Eo *obj EINA_UNUSED
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(pd->glim == image, EINA_FALSE);
if (pd->was_render)
{
Render_Engine_GL_Generic *re = pd->evas->engine.data.output;
Evas_Engine_GL_Context *gc;
gc = re->window_gl_context_get(re->software.ob);
pd->glim = evas_gl_common_image_surface_detach(gc, pd->glim);
}
evas_gl_common_image_free(pd->glim);
return EINA_TRUE;
@ -270,12 +277,15 @@ _evas_ector_gl_buffer_ector_buffer_map(Eo *obj EINA_UNUSED, Evas_Ector_GL_Buffer
pxs = 4;
}
map->map_id = ++_map_id;
map->base_size = len * pxs;
map->length = (W * h + w - W) * pxs;
if (stride) *stride = W * pxs;
if (length) *length = map->length;
EINA_INLIST_PREPEND(pd->maps, map);;
MAP_DUMP(im, "in");
EINA_INLIST_PREPEND(pd->maps, map);
return map->ptr;
on_fail:
@ -311,20 +321,28 @@ _evas_ector_gl_buffer_ector_buffer_unmap(Eo *obj EINA_UNUSED, Evas_Ector_GL_Buff
if (map->im)
{
MAP_DUMP(map->im, "out_w_free");
pd->glim = evas_gl_common_image_surface_update(gc, map->im);
evas_gl_common_image_free(old_glim);
}
else
{
MAP_DUMP(old_glim, "out_w_nofree");
pd->glim = evas_gl_common_image_surface_update(gc, old_glim);
}
}
else
{
if (map->im)
ENFN->image_free(ENDT, map->im);
{
MAP_DUMP(map->im, "out_ro_free");
ENFN->image_free(ENDT, map->im);
}
else
ENFN->image_data_put(ENDT, pd->glim, map->image_data);
{
MAP_DUMP(pd->glim, "out_ro_nofree");
ENFN->image_data_put(ENDT, pd->glim, map->image_data);
}
}
if (map->allocated)
free(map->base_data);

View File

@ -82,8 +82,7 @@ _evas_ector_gl_image_buffer_evas_ector_buffer_engine_image_set(Eo *obj, Evas_Ect
EOLIAN static void *
_evas_ector_gl_image_buffer_evas_ector_buffer_drawable_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_GL_Image_Buffer_Data *pd,
Eina_Bool update EINA_UNUSED)
Evas_Ector_GL_Image_Buffer_Data *pd)
{
evas_gl_common_image_ref(pd->glim);
return pd->glim;

View File

@ -28,7 +28,7 @@
#define EVAS_GL_UPDATE_TILE_SIZE 16
static int _evas_engine_GL_log_dom = -1;
int _evas_engine_GL_log_dom = -1;
#undef ERR
#undef DBG

View File

@ -6,6 +6,8 @@
#include "evas_ector_buffer.eo.h"
#include "../Evas_Engine_GL_Generic.h"
extern int _evas_engine_GL_log_dom;
typedef Eina_Bool (* GL_Filter_Apply_Func) (Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd);
GL_Filter_Apply_Func gl_filter_blend_func_get(Evas_Filter_Command *cmd);
//Software_Filter_Func gl_filter_blur_func_get(Evas_Filter_Command *cmd);
@ -16,4 +18,15 @@ GL_Filter_Apply_Func gl_filter_blend_func_get(Evas_Filter_Command *cmd);
//Software_Filter_Func gl_filter_mask_func_get(Evas_Filter_Command *cmd);
//Software_Filter_Func gl_filter_transform_func_get(Evas_Filter_Command *cmd);
#undef DBG
#undef INF
#undef WRN
#undef ERR
#undef CRI
#define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_GL_log_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_evas_engine_GL_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_GL_log_dom, __VA_ARGS__)
#define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_GL_log_dom, __VA_ARGS__)
#define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_GL_log_dom, __VA_ARGS__)
#endif // GL_ENGINE_FILTER_H

View File

@ -1,5 +1,162 @@
#include "gl_engine_filter.h"
// Copied logic from SW engine
static Eina_Bool
_mapped_blend(Evas_Engine_GL_Context *gc,
Evas_GL_Image *image,
Evas_Filter_Fill_Mode fillmode,
int sx, int sy, int sw, int sh,
int dx, int dy, int dw, int dh)
{
int right = 0, bottom = 0, left = 0, top = 0;
int row, col, rows, cols;
Eina_Bool ret = EINA_TRUE;
EINA_SAFETY_ON_FALSE_RETURN_VAL((sx == 0) && (sy == 0), EINA_FALSE);
if (fillmode == EVAS_FILTER_FILL_MODE_NONE)
{
DBG("blend: %d,%d,%d,%d --> %d,%d,%d,%d", sx, sy, sw, sh, dx, dy, sw, sh);
evas_gl_common_image_draw(gc, image, sx, sy, sw, sh, dx, dy, sw, sh, EINA_TRUE);
return EINA_TRUE;
}
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_X)
{
if (dx > 0) left = dx % sw;
else if (dx < 0) left = sw + (dx % sw);
cols = (dw /*- left*/) / sw;
if (left > 0)
right = dw - (sw * (cols - 1)) - left;
else
right = dw - (sw * cols);
dx = 0;
}
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
{
cols = 0;
dx = 0;
}
else
{
// FIXME: Probably wrong if dx != 0
cols = 0;
dw -= dx;
}
if (fillmode & EVAS_FILTER_FILL_MODE_REPEAT_Y)
{
if (dy > 0) top = dy % sh;
else if (dy < 0) top = sh + (dy % sh);
rows = (dh /*- top*/) / sh;
if (top > 0)
bottom = dh - (sh * (rows - 1)) - top;
else
bottom = dh - (sh * rows);
dy = 0;
}
else if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
{
rows = 0;
dy = 0;
}
else
{
// FIXME: Probably wrong if dy != 0
rows = 0;
dh -= dy;
}
if (top > 0) row = -1;
else row = 0;
for (; row <= rows; row++)
{
int src_x, src_y, src_w, src_h;
int dst_x, dst_y, dst_w, dst_h;
if (row == -1 && top > 0)
{
// repeat only
src_h = top;
src_y = sh - top;
dst_y = dy;
dst_h = src_h;
}
else if (row == rows && bottom > 0)
{
// repeat only
src_h = bottom;
src_y = 0;
dst_y = top + dy + row * sh;
dst_h = src_h;
}
else
{
src_y = 0;
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
{
src_h = sh;
dst_h = dh;
dst_y = 0;
}
else
{
dst_y = top + dy + row * sh;
src_h = MIN(dh - dst_y, sh);
dst_h = src_h;
}
}
if (src_h <= 0 || dst_h <= 0) break;
if (left > 0) col = -1;
else col = 0;
for (; col <= cols; col++)
{
if (col == -1 && left > 0)
{
// repeat only
src_w = left;
src_x = sw - left;
dst_x = dx;
dst_w = src_w;
}
else if (col == cols && right > 0)
{
// repeat only
src_w = right;
src_x = 0;
dst_x = left + dx + col * sw;
dst_w = src_w;
}
else
{
src_x = 0;
if (fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
{
src_w = sw;
dst_w = dw;
dst_x = 0;
}
else
{
dst_x = left + dx + col * sw;
src_w = MIN(dw - dst_x, sw);
dst_w = src_w;
}
}
if (src_w <= 0 || dst_w <= 0) break;
DBG("blend: [%d,%d] %d,%d,%dx%d --> %d,%d,%dx%d "
"(src %dx%d, dst %dx%d)",
col, row, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h, sw, sh, dw, dh);
evas_gl_common_image_draw(gc, image, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h, EINA_TRUE);
}
}
return ret;
}
static Eina_Bool
_gl_filter_blend(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
{
@ -10,12 +167,12 @@ _gl_filter_blend(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
re->window_use(re->software.ob);
gc = re->window_gl_context_get(re->software.ob);
image = evas_ector_buffer_drawable_image_get(cmd->input->buffer, EINA_TRUE);
image = evas_ector_buffer_drawable_image_get(cmd->input->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(image->tex, EINA_FALSE);
surface = evas_ector_buffer_render_image_get(cmd->output->buffer, EINA_FALSE);
surface = evas_ector_buffer_render_image_get(cmd->output->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface->tex, EINA_FALSE);
@ -23,15 +180,15 @@ _gl_filter_blend(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
EINA_SAFETY_ON_FALSE_RETURN_VAL(surface->tex->pt->fb != 0, EINA_FALSE);
evas_gl_common_context_target_surface_set(gc, surface);
// TODO: mapped render iteration
dc_save = gc->dc;
gc->dc = evas_common_draw_context_new();
evas_common_draw_context_set_multiplier(gc->dc, cmd->draw.R, cmd->draw.G, cmd->draw.B, cmd->draw.A);
gc->dc->render_op = _gfx_to_evas_render_op(cmd->draw.rop);
evas_gl_common_image_draw(gc, image, 0, 0, image->w, image->h,
cmd->draw.ox, cmd->draw.oy, image->w, image->h,
EINA_TRUE);
DBG("blend %d @%p -> %d @%p", cmd->input->id, cmd->input->buffer,
cmd->output->id, cmd->output->buffer);
_mapped_blend(gc, image, cmd->draw.fillmode, 0, 0, image->w, image->h,
cmd->draw.ox, cmd->draw.oy, cmd->output->w, cmd->output->h);
evas_common_draw_context_free(gc->dc);
gc->dc = dc_save;

View File

@ -39,8 +39,7 @@ _evas_ector_software_buffer_evas_ector_buffer_engine_image_set(Eo *obj, Evas_Ect
EOLIAN static void *
_evas_ector_software_buffer_evas_ector_buffer_drawable_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_Software_Buffer_Data *pd,
Eina_Bool update EINA_UNUSED)
Evas_Ector_Software_Buffer_Data *pd)
{
evas_cache_image_ref(&pd->image->cache_entry);
return pd->image;
@ -48,8 +47,7 @@ _evas_ector_software_buffer_evas_ector_buffer_drawable_image_get(Eo *obj EINA_UN
EOLIAN static void *
_evas_ector_software_buffer_evas_ector_buffer_render_image_get(Eo *obj EINA_UNUSED,
Evas_Ector_Software_Buffer_Data *pd,
Eina_Bool update EINA_UNUSED)
Evas_Ector_Software_Buffer_Data *pd)
{
evas_cache_image_ref(&pd->image->cache_entry);
return pd->image;

View File

@ -208,7 +208,7 @@ _filter_displace_cpu_alpha(Evas_Filter_Command *cmd)
EINA_SAFETY_ON_FALSE_RETURN_VAL(h == cmd->output->h, EINA_FALSE);
src = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
dst = _buffer_map_all(cmd->output->buffer, &dst_len, E_READ, E_ALPHA, &dst_stride);
dst = _buffer_map_all(cmd->output->buffer, &dst_len, E_READ | E_WRITE, E_ALPHA, &dst_stride);
stretch = cmd->displacement.flags & EVAS_FILTER_DISPLACE_STRETCH;
smooth = cmd->displacement.flags & EVAS_FILTER_DISPLACE_LINEAR;
map_w = cmd->mask->w;

View File

@ -16,9 +16,6 @@ eng_filter_mask_func_get(Evas_Filter_Command *cmd)
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask, NULL);
//EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input->buffer, NULL);
//EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output->buffer, NULL);
//EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask->buffer, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL((cmd->input->w > 0) && (cmd->input->h > 0), NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL((cmd->mask->w > 0) && (cmd->mask->h > 0), NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->input->w == cmd->output->w, NULL);