diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index a37fe405d1..ef2710b72e 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -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; diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index 3e7548a97f..b48955ed44 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -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); diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index a2f7d68a60..48de69e4c7 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -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) diff --git a/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c b/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c index 636b9a71e5..66416ddd7d 100644 --- a/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c +++ b/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c @@ -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;