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_Buffer *in, Evas_Filter_Buffer *out,
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)
{
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:
* - Always split X and Y passes (only one pass if 1D blur)
* - TODO: Repeat blur for large radius
* - TODO: Scale down & up for cheap blur
* - The rest is all up to the engine!
* - Create intermediate buffer T (variable size)
* - Downscale to buffer T
* - Apply X blur kernel
* - 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)
{
dx_out = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 1);
if (!dx_out) goto fail;
dy_in = dx_out;
tmp = evas_filter_temporary_buffer_get(ctx, 0, 0, in->alpha_only, 1);
if (!tmp) goto fail;
dy_in = dx_out = tmp;
}
else
{
@ -570,8 +599,8 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx,
if (dx)
{
XDBG("Add GL blur %d -> %d (%dx%d px)", in->id, dx_out->id, dx, 0);
cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, in, NULL, dx_out);
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, dx_in, NULL, dx_out);
if (!cmd) goto fail;
cmd->blur.type = type;
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);
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);
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);
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
evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
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 sx, sy, sw, sh, pw, ph;
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4;
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph;
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
GLfloat offsetx, offsety;
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;
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, &nomul, NULL);
_filter_data_flush(gc, prog);
EINA_SAFETY_ON_NULL_RETURN(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);
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_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);
// Set blur properties... TODO
_filter_data_prepare(gc, pn, prog, 1);
filter_data = gc->pipe[pn].array.filter_data;
filter_data[0] = radius;
filter_data[1] = horiz ? w : h;
sx = 0;
sy = 0;
sw = w;
sh = h;
filter_data[1] = horiz ? sw : sh;
pw = tex->pt->w;
ph = tex->pt->h;
@ -3524,7 +3519,7 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
tx4 = ((double)(offsetx) + ox4) / pw;
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);
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;
RGBA_Draw_Context *dc_save;
Eina_Bool horiz;
double radius;
int x, y, w, h;
double sx, sy, sw, sh, ssx, ssy, ssw, ssh, dx, dy, dw, dh, radius;
int nx, ny, nw, nh;
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);
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,
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);
gc->dc = dc_save;