evas filters: Use GL downscaling for blur

This will improve the performance a lot. Now remains to figure
out the best values for downscaling and improve the actual blur
shader as well.
This commit is contained in:
Jean-Philippe Andre 2017-03-20 20:20:21 +09:00
parent d56f9afa40
commit a9ddeeb4fb
4 changed files with 68 additions and 33 deletions

View File

@ -543,24 +543,53 @@ static Evas_Filter_Command *
evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx,
Evas_Filter_Buffer *in, Evas_Filter_Buffer *out, Evas_Filter_Buffer *in, Evas_Filter_Buffer *out,
Evas_Filter_Blur_Type type, Evas_Filter_Blur_Type type,
int dx, int dy, int ox, int oy, int count, int rx, int ry, int ox, int oy, int count,
int R, int G, int B, int A) int R, int G, int B, int A)
{ {
Evas_Filter_Command *cmd; Evas_Filter_Command *cmd;
Evas_Filter_Buffer *dx_out, *dy_in; Evas_Filter_Buffer *dx_in, *dx_out, *dy_in, *tmp = NULL;
int down_x, down_y, dx, dy;
/* GL blur implementation: /* GL blur implementation:
* - Always split X and Y passes (only one pass if 1D blur) * - Create intermediate buffer T (variable size)
* - TODO: Repeat blur for large radius * - Downscale to buffer T
* - TODO: Scale down & up for cheap blur * - Apply X blur kernel
* - The rest is all up to the engine! * - Apply Y blur kernel while scaling up
*
* - TODO: Fix distortion X vs. Y
* - TODO: Calculate best scaline and blur radius
* - TODO: Add post-processing? (2D single-pass)
*/ */
dx = rx;
dy = ry;
dx_in = in;
if (type == EVAS_FILTER_BLUR_DEFAULT)
{
down_x = MAX((1 << evas_filter_smallest_pow2_larger_than(dx / 2) / 2), 1);
down_y = MAX((1 << evas_filter_smallest_pow2_larger_than(dy / 2) / 2), 1);
tmp = evas_filter_temporary_buffer_get(ctx, ctx->w / down_x, ctx->h / down_y,
in->alpha_only, EINA_TRUE);
if (!tmp) goto fail;
// FIXME: Fix logic here. This is where the smarts are! Now it's dumb.
dx = rx / down_x;
dy = ry / down_y;
XDBG("Add GL downscale %d (%dx%d) -> %d (%dx%d)", in->id, in->w, in->h, tmp->id, tmp->w, tmp->h);
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLEND, in, NULL, tmp);
if (!cmd) goto fail;
cmd->draw.fillmode = EVAS_FILTER_FILL_MODE_STRETCH_XY;
dx_in = tmp;
}
if (dx && dy) if (dx && dy)
{ {
dx_out = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 1); tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 1);
if (!dx_out) goto fail; if (!tmp) goto fail;
dy_in = dx_out; dy_in = dx_out = tmp;
} }
else else
{ {
@ -570,8 +599,8 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx,
if (dx) if (dx)
{ {
XDBG("Add GL blur %d -> %d (%dx%d px)", in->id, dx_out->id, dx, 0); XDBG("Add GL blur %d -> %d (%dx%d px)", dx_in->id, dx_out->id, dx, 0);
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, in, NULL, dx_out); cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, dx_in, NULL, dx_out);
if (!cmd) goto fail; if (!cmd) goto fail;
cmd->blur.type = type; cmd->blur.type = type;
cmd->blur.dx = dx; cmd->blur.dx = dx;

View File

@ -651,7 +651,7 @@ void evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc
int x, int y, int w, int h, double dx, double dy, Eina_Bool nearest); int x, int y, int w, int h, double dx, double dy, Eina_Bool nearest);
void evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex, void evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex,
int x, int y, int w, int h, const uint8_t *points, int channel); int x, int y, int w, int h, const uint8_t *points, int channel);
void evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex, int x, int y, int w, int h, double radius, Eina_Bool horiz); void evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh, double radius, Eina_Bool horiz);
int evas_gl_common_shader_program_init(Evas_GL_Shared *shared); int evas_gl_common_shader_program_init(Evas_GL_Shared *shared);
void evas_gl_common_shader_program_shutdown(Evas_GL_Shared *shared); void evas_gl_common_shader_program_shutdown(Evas_GL_Shared *shared);

View File

@ -3430,11 +3430,11 @@ evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc,
void void
evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex, Evas_GL_Texture *tex,
int x, int y, int w, int h, double sx, double sy, double sw, double sh,
double dx, double dy, double dw, double dh,
double radius, Eina_Bool horiz) double radius, Eina_Bool horiz)
{ {
double sx, sy, sw, sh, pw, ph; double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph;
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4;
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4; GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
GLfloat offsetx, offsety; GLfloat offsetx, offsety;
int r, g, b, a, nomul = 0, pn; int r, g, b, a, nomul = 0, pn;
@ -3452,14 +3452,14 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
blend = EINA_FALSE; blend = EINA_FALSE;
prog = evas_gl_common_shader_program_get(gc, type, NULL, 0, r, g, b, a, prog = evas_gl_common_shader_program_get(gc, type, NULL, 0, r, g, b, a,
w, h, w, h, smooth, tex, EINA_FALSE, sw, sh, dw, dh, smooth, tex, EINA_FALSE,
NULL, EINA_FALSE, EINA_FALSE, 0, 0, NULL, EINA_FALSE, EINA_FALSE, 0, 0,
NULL, &nomul, NULL); NULL, &nomul, NULL);
_filter_data_flush(gc, prog); _filter_data_flush(gc, prog);
EINA_SAFETY_ON_NULL_RETURN(prog); EINA_SAFETY_ON_NULL_RETURN(prog);
pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog, pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog,
x, y, w, h, blend, smooth, sx, sy, dw, dh, blend, smooth,
0, 0, 0, 0, 0, EINA_FALSE); 0, 0, 0, 0, 0, EINA_FALSE);
gc->pipe[pn].region.type = type; gc->pipe[pn].region.type = type;
@ -3486,19 +3486,14 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_mask = 0; gc->pipe[pn].array.use_mask = 0;
gc->pipe[pn].array.use_masksam = 0; gc->pipe[pn].array.use_masksam = 0;
pipe_region_expand(gc, pn, x, y, w, h); pipe_region_expand(gc, pn, dx, dy, dw, dh);
PIPE_GROW(gc, pn, 6); PIPE_GROW(gc, pn, 6);
// Set blur properties... TODO // Set blur properties... TODO
_filter_data_prepare(gc, pn, prog, 1); _filter_data_prepare(gc, pn, prog, 1);
filter_data = gc->pipe[pn].array.filter_data; filter_data = gc->pipe[pn].array.filter_data;
filter_data[0] = radius; filter_data[0] = radius;
filter_data[1] = horiz ? w : h; filter_data[1] = horiz ? sw : sh;
sx = 0;
sy = 0;
sw = w;
sh = h;
pw = tex->pt->w; pw = tex->pt->w;
ph = tex->pt->h; ph = tex->pt->h;
@ -3524,7 +3519,7 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
tx4 = ((double)(offsetx) + ox4) / pw; tx4 = ((double)(offsetx) + ox4) / pw;
ty4 = ((double)(offsety) + oy4) / ph; ty4 = ((double)(offsety) + oy4) / ph;
PUSH_6_VERTICES(pn, x, y, w, h); PUSH_6_VERTICES(pn, dx, dy, dw, dh);
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4); PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
if (!nomul) if (!nomul)

View File

@ -7,16 +7,11 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
Evas_GL_Image *image, *surface; Evas_GL_Image *image, *surface;
RGBA_Draw_Context *dc_save; RGBA_Draw_Context *dc_save;
Eina_Bool horiz; Eina_Bool horiz;
double radius; double sx, sy, sw, sh, ssx, ssy, ssw, ssh, dx, dy, dw, dh, radius;
int x, y, w, h; int nx, ny, nw, nh;
DEBUG_TIME_BEGIN(); DEBUG_TIME_BEGIN();
x = cmd->draw.ox;
y = cmd->draw.oy;
w = cmd->input->w;
h = cmd->input->h;
re->window_use(re->software.ob); re->window_use(re->software.ob);
gc = re->window_gl_context_get(re->software.ob); gc = re->window_gl_context_get(re->software.ob);
@ -52,7 +47,23 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
cmd->input->id, cmd->input->buffer, cmd->output->id, cmd->output->buffer, cmd->input->id, cmd->input->buffer, cmd->output->id, cmd->output->buffer,
radius, horiz ? "X" : "Y"); radius, horiz ? "X" : "Y");
evas_gl_common_filter_blur_push(gc, image->tex, x, y, w, h, radius, horiz); sx = 0;
sy = 0;
sw = cmd->input->w;
sh = cmd->input->h;
dx = cmd->draw.ox;
dy = cmd->draw.oy;
dw = cmd->output->w;
dh = cmd->output->h;
nx = dx; ny = dy; nw = dw; nh = dh;
RECTS_CLIP_TO_RECT(nx, ny, nw, nh, 0, 0, cmd->output->w, cmd->output->h);
ssx = (double)sx + ((double)(sw * (nx - dx)) / (double)(dw));
ssy = (double)sy + ((double)(sh * (ny - dy)) / (double)(dh));
ssw = ((double)sw * (double)(nw)) / (double)(dw);
ssh = ((double)sh * (double)(nh)) / (double)(dh);
evas_gl_common_filter_blur_push(gc, image->tex, ssx, ssy, ssw, ssh, dx, dy, dw, dh, radius, horiz);
evas_common_draw_context_free(gc->dc); evas_common_draw_context_free(gc->dc);
gc->dc = dc_save; gc->dc = dc_save;