From 5bce7120f1c2b15ee23a874e4910316569a435c8 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 25 Jan 2017 18:06:29 +0900 Subject: [PATCH] evas filter: Implement blur filter in pure GL Wait a second though, this implementation is not only incomplete (no support for box vs. gaussian blur), it's also insanely bad in terms of performance. Small radii may work fine, but at least blurs render properly in GL with this patch (no more glReadPixels!). The shader needs a lot of love, including in particular: - support for 1D box blur single pass - support for 1D gaussian (or sine) blur - use linear interpolation and N-tap filters - separation of 2D blur in two passes (high-level logic) - potentially separation of large 1D blurs in 2 or more passes knowing that 2sigma == sigma + sigma when it comes to the gaussian bell curve. --- src/Makefile_Evas.am | 1 + src/bin/elementary/test_gfx_filters.c | 2 + src/lib/evas/filters/evas_filter.c | 30 +++- .../evas/engines/gl_common/evas_gl_common.h | 4 +- .../evas/engines/gl_common/evas_gl_context.c | 145 ++++++++++++++++-- .../evas/engines/gl_common/evas_gl_shader.c | 9 +- .../gl_common/shader/evas_gl_shaders.x | 71 ++++++++- .../engines/gl_common/shader/fragment.glsl | 69 +++++++++ .../evas/engines/gl_common/shader/vertex.glsl | 14 +- .../evas/engines/gl_generic/evas_engine.c | 2 +- .../gl_generic/filters/gl_engine_filter.h | 2 +- .../gl_generic/filters/gl_filter_blur.c | 63 ++++++++ 12 files changed, 382 insertions(+), 30 deletions(-) create mode 100644 src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index b270f763e8..5345b9d7ba 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -844,6 +844,7 @@ modules/evas/engines/gl_generic/evas_ector_gl_buffer.c \ modules/evas/engines/gl_generic/evas_ector_gl_image_buffer.c \ modules/evas/engines/gl_generic/filters/gl_engine_filter.h \ modules/evas/engines/gl_generic/filters/gl_filter_blend.c \ +modules/evas/engines/gl_generic/filters/gl_filter_blur.c \ modules/evas/engines/gl_generic/filters/gl_filter_curve.c \ modules/evas/engines/gl_generic/filters/gl_filter_displace.c \ modules/evas/engines/gl_generic/filters/gl_filter_fill.c \ diff --git a/src/bin/elementary/test_gfx_filters.c b/src/bin/elementary/test_gfx_filters.c index d67f616ac8..94036c364f 100644 --- a/src/bin/elementary/test_gfx_filters.c +++ b/src/bin/elementary/test_gfx_filters.c @@ -47,6 +47,8 @@ static const Filter_Image images_anim[] = { /* builtin filter examples */ static const Filter templates[] = { { "Custom", NULL, NULL }, + { "BLUR", + "blur { 15, color = 'darkblue' }", NULL }, { "Simple blend", "blend { color = 'darkblue' }", NULL }, { "Black shadow", diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index b343b9181d..bb761f32a8 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -548,11 +548,6 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, 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); @@ -570,8 +565,6 @@ 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 == out) out->dirty = EINA_FALSE; - ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A); color = ARGB_JOIN(A, R, G, B); if (!color) @@ -580,6 +573,29 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, return _command_new(ctx, EVAS_FILTER_MODE_SKIP, NULL, NULL, NULL); } + if (ctx->gl) + { + // GL engine: single pass! + XDBG("Add GL blur %d -> %d (%dx%d px)", in->id, out->id, dx, dy); + cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, in, NULL, out); + if (!cmd) goto fail; + cmd->blur.type = type; + cmd->blur.dx = dx; + cmd->blur.dy = dy; + cmd->blur.count = count; + cmd->draw.ox = ox; + cmd->draw.oy = oy; + DRAW_COLOR_SET(R, G, B, A); + return cmd; + } + + // 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. + + if (in == out) out->dirty = EINA_FALSE; + render_op = ENFN->context_render_op_get(ENDT, drawctx); override = (render_op == EVAS_RENDER_COPY); 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 463bd248c2..2ecc94fe0b 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -108,7 +108,7 @@ struct _Evas_GL_Program GLuint mvp, rotation_id; } uniform; struct { - GLuint loc_filter_data[3]; + GLint loc_filter_data[3]; Eina_Bool known_locations; } attribute; GLuint prog; @@ -245,6 +245,7 @@ enum _Shader_Type { SHD_MAP, SHD_FILTER_DISPLACE, SHD_FILTER_CURVE, + SHD_FILTER_BLUR, SHD_TYPE_LAST }; @@ -650,6 +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 dx, double dy); 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 cd3584d200..cc432eaf70 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -1205,6 +1205,9 @@ error: #define PIPE_FREE(x) \ do { _pipebuf_free(x); (x) = NULL; } while (0) +#define FREE(x) \ + do { free(x); (x) = NULL; } while (0) + typedef struct _Pipebuf { int skipped, alloc; @@ -1380,7 +1383,7 @@ evas_gl_common_context_free(Evas_Engine_GL_Context *gc) PIPE_FREE(gc->pipe[i].array.texsam); PIPE_FREE(gc->pipe[i].array.mask); PIPE_FREE(gc->pipe[i].array.masksam); - PIPE_FREE(gc->pipe[i].array.filter_data); + FREE(gc->pipe[i].array.filter_data); } } @@ -3135,6 +3138,25 @@ _filter_data_flush(Evas_Engine_GL_Context *gc, Evas_GL_Program *prog) } } +static inline void +_filter_data_prepare(Evas_Engine_GL_Context *gc, int pn, + Evas_GL_Program *prog, int count) +{ + gc->pipe[pn].array.filter_data_count = count; + gc->pipe[pn].array.filter_data = malloc(count * 2 * sizeof(GLfloat)); + + if (!prog->attribute.known_locations) + { + for (int k = 0; k < count; k++) + { + char name[32]; + + sprintf(name, "filter_data_%d", k); + prog->attribute.loc_filter_data[k] = glGetAttribLocation(prog->prog, name); + } + } +} + void evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex, Evas_GL_Texture *map_tex, @@ -3199,19 +3221,7 @@ evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc, // displace properties gc->pipe[pn].shader.filter.map_tex = map_tex->pt->texture; gc->pipe[pn].shader.filter.map_nearest = nearest; - gc->pipe[pn].array.filter_data_count = 3; - gc->pipe[pn].array.filter_data = malloc(6 * sizeof(GLfloat)); - - if (!prog->attribute.known_locations) - { - for (int k = 0; k < gc->pipe[pn].array.filter_data_count; k++) - { - char name[32]; - - sprintf(name, "filter_data_%d", k); - prog->attribute.loc_filter_data[k] = glGetAttribLocation(prog->prog, name); - } - } + _filter_data_prepare(gc, pn, prog, 3); sx = x; sy = y; @@ -3415,6 +3425,111 @@ evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc, if (!nomul) PUSH_6_COLORS(pn, r, g, b, a); +} + +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 dx, double dy) +{ + double sx, sy, sw, sh, pw, ph; + double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4; + GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4; + GLfloat offsetx, offsety; + int r, g, b, a, nomul = 0, pn; + Evas_GL_Program *prog; + GLfloat *filter_data; + Eina_Bool blend = EINA_TRUE; + Eina_Bool smooth = EINA_TRUE; + + r = R_VAL(&gc->dc->mul.col); + g = G_VAL(&gc->dc->mul.col); + b = B_VAL(&gc->dc->mul.col); + a = A_VAL(&gc->dc->mul.col); + if (gc->dc->render_op == EVAS_RENDER_COPY) + blend = EINA_FALSE; + + prog = evas_gl_common_shader_program_get(gc, SHD_FILTER_BLUR, NULL, 0, r, g, b, a, + w, h, w, h, 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(SHD_FILTER_BLUR, gc, tex, NULL, prog, + x, y, w, h, blend, smooth, + 0, 0, 0, 0, 0, EINA_FALSE); + + gc->pipe[pn].region.type = SHD_FILTER_BLUR; + gc->pipe[pn].shader.prog = prog; + gc->pipe[pn].shader.cur_tex = tex->pt->texture; + gc->pipe[pn].shader.cur_texm = 0; + gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D; + gc->pipe[pn].shader.smooth = smooth; + gc->pipe[pn].shader.mask_smooth = 0; + gc->pipe[pn].shader.blend = blend; + gc->pipe[pn].shader.render_op = gc->dc->render_op; + gc->pipe[pn].shader.clip = 0; + gc->pipe[pn].shader.cx = 0; + gc->pipe[pn].shader.cy = 0; + gc->pipe[pn].shader.cw = 0; + gc->pipe[pn].shader.ch = 0; + gc->pipe[pn].array.line = 0; + gc->pipe[pn].array.use_vertex = 1; + gc->pipe[pn].array.use_color = !nomul; + gc->pipe[pn].array.use_texuv = 1; + gc->pipe[pn].array.use_texuv2 = 0; + gc->pipe[pn].array.use_texuv3 = 0; + gc->pipe[pn].array.use_texsam = 0; + gc->pipe[pn].array.use_mask = 0; + gc->pipe[pn].array.use_masksam = 0; + + pipe_region_expand(gc, pn, x, y, w, h); + PIPE_GROW(gc, pn, 6); + + // Set blur properties... TODO + _filter_data_prepare(gc, pn, prog, 2); + filter_data = gc->pipe[pn].array.filter_data; + filter_data[0] = dx; + filter_data[1] = dy; + filter_data[2] = w; + filter_data[3] = h; + + sx = 0; + sy = 0; + sw = w; + sh = h; + + pw = tex->pt->w; + ph = tex->pt->h; + + ox1 = sx; + oy1 = sy; + ox2 = sx + sw; + oy2 = sy; + ox3 = sx + sw; + oy3 = sy + sh; + ox4 = sx; + oy4 = sy + sh; + + offsetx = tex->x; + offsety = tex->y; + + tx1 = ((double)(offsetx) + ox1) / pw; + ty1 = ((double)(offsety) + oy1) / ph; + tx2 = ((double)(offsetx) + ox2) / pw; + ty2 = ((double)(offsety) + oy2) / ph; + tx3 = ((double)(offsetx) + ox3) / pw; + ty3 = ((double)(offsety) + oy3) / ph; + tx4 = ((double)(offsetx) + ox4) / pw; + ty4 = ((double)(offsety) + oy4) / ph; + + PUSH_6_VERTICES(pn, x, y, w, h); + PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4); + + if (!nomul) + PUSH_6_COLORS(pn, r, g, b, a); shader_array_flush(gc); } @@ -4180,7 +4295,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc) PIPE_FREE(gc->pipe[i].array.texsam); PIPE_FREE(gc->pipe[i].array.mask); PIPE_FREE(gc->pipe[i].array.masksam); - PIPE_FREE(gc->pipe[i].array.filter_data); + FREE(gc->pipe[i].array.filter_data); gc->pipe[i].array.num = 0; gc->pipe[i].array.alloc = 0; diff --git a/src/modules/evas/engines/gl_common/evas_gl_shader.c b/src/modules/evas/engines/gl_common/evas_gl_shader.c index fd19efb729..6f8eb37d49 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_shader.c +++ b/src/modules/evas/engines/gl_common/evas_gl_shader.c @@ -42,8 +42,9 @@ typedef enum { SHADER_FLAG_RGB_A_PAIR = (1 << 20), SHADER_FLAG_FILTER_DISPLACE = (1 << 21), SHADER_FLAG_FILTER_CURVE = (1 << 22), + SHADER_FLAG_FILTER_BLUR = (1 << 23), } Shader_Flag; -#define SHADER_FLAG_COUNT 23 +#define SHADER_FLAG_COUNT 24 static const char *_shader_flags[SHADER_FLAG_COUNT] = { "TEX", @@ -68,7 +69,8 @@ static const char *_shader_flags[SHADER_FLAG_COUNT] = { "ALPHA", "RGB_A_PAIR", "FILTER_DISPLACE", - "FILTER_CURVE" + "FILTER_CURVE", + "FILTER_BLUR" }; static Eina_Bool compiler_released = EINA_FALSE; @@ -785,6 +787,9 @@ evas_gl_common_shader_flags_get(Evas_GL_Shared *shared, Shader_Type type, case SHD_FILTER_CURVE: flags |= SHADER_FLAG_FILTER_CURVE; break; + case SHD_FILTER_BLUR: + flags |= SHADER_FLAG_FILTER_BLUR; + break; default: CRI("Impossible shader type."); return 0; diff --git a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x index 830a3fb1ac..9bbef31c5b 100644 --- a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x +++ b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x @@ -20,6 +20,8 @@ static const char fragment_glsl[] = "#else\n" "# define SAMPLER_EXTERNAL_OES sampler2D\n" "#endif\n" + "#define M_PI 3.141592653589793238462643383279502884\n" + "#define M_PI_2 1.570796326794896619231321691639751442\n" "#ifndef SHD_NOMUL\n" "varying vec4 col;\n" "#endif\n" @@ -89,11 +91,22 @@ static const char fragment_glsl[] = "#ifdef SHD_FILTER_CURVE\n" "uniform sampler2D tex_filter;\n" "#endif\n" + "#ifdef SHD_FILTER_BLUR\n" + "varying vec2 blur_radius;\n" + "varying vec2 blur_divider;\n" + "#endif\n" + "// ----------------------------------------------------------------------------\n" + "#ifndef SHD_FILTER_BLUR\n" "void main()\n" "{\n" "#if defined(SHD_EXTERNAL) || defined(SHD_TEX)\n" " vec2 coord = tex_c;\n" "#endif\n" + "#else // SHD_FILTER_BLUR\n" + "vec4 fetch_pixel(float ox, float oy)\n" + "{\n" + " vec2 coord = tex_c + vec2(ox, oy);\n" + "#endif // SHD_FILTER_BLUR\n" " vec4 c;\n" "#ifdef SHD_FILTER_DISPLACE\n" " vec2 dxy = texture2D(tex_filter, tex_c).rg * displace_vector;\n" @@ -195,8 +208,8 @@ static const char fragment_glsl[] = " texture2D(tex_filter, vec2(c.g / old_alpha, 0.0)).g * new_alpha,\n" " texture2D(tex_filter, vec2(c.b / old_alpha, 0.0)).b * new_alpha,\n" " new_alpha);\n" - " //c = vec4(new_alpha, new_alpha, new_alpha, new_alpha);\n" "#endif\n" + "#ifndef SHD_FILTER_BLUR\n" " gl_FragColor =\n" " c\n" "#ifndef SHD_NOMUL\n" @@ -209,7 +222,50 @@ static const char fragment_glsl[] = " * fa\n" "#endif\n" " ;\n" - "}\n"; + "}\n" + "#else // SHD_FILTER_BLUR\n" + " return c;\n" + "}\n" + "void main()\n" + "{\n" + " float x, y, div_x, div_y;\n" + " float rx = blur_radius.x;\n" + " float ry = blur_radius.y;\n" + " vec4 acc = vec4(0.,0.,0.,0.);\n" + " vec4 c;\n" + " div_x = blur_divider.x;\n" + " div_y = blur_divider.y;\n" + " float diam_x = rx * 2.0 + 1.0;\n" + " float diam_y = ry * 2.0 + 1.0;\n" + " float div = 0.0;\n" + "#if 1\n" + " // This is completely insane... but renders properly :)\n" + " for (y = -ry; y <= ry; y += 8.0)\n" + " {\n" + " float wy = (y + ry) / (diam_y - 1.0) * 6.0 - 3.0;\n" + " wy = (sin(wy + M_PI_2) + 1.0) / 2.0;\n" + " for (x = -rx; x <= rx; x += 8.0)\n" + " {\n" + " float wx = (x + rx) / (diam_x - 1.0) * 6.0 - 3.0;\n" + " wx = (sin(wx + M_PI_2) + 1.0) / 2.0;\n" + " vec4 px = fetch_pixel(x / div_x, y / div_y);\n" + " acc += px * wx * wy;\n" + " div += wx * wy;\n" + " }\n" + " }\n" + "#else\n" + " vec4 px = fetch_pixel(0.0, 0.0);\n" + " div = 1.0;\n" + " acc += px;\n" + "#endif\n" + " c = acc / div;\n" + "#ifndef SHD_NOMUL\n" + " gl_FragColor = c * col;\n" + "#else\n" + " gl_FragColor = c;\n" + "#endif\n" + "}\n" + "#endif // SHD_FILTER_BLUR\n"; static const char vertex_glsl[] = "/* General-purpose vertex shader for all operations in Evas.\n" @@ -282,6 +338,13 @@ static const char vertex_glsl[] = "varying vec2 displace_min;\n" "varying vec2 displace_max;\n" "#endif\n" + "/* Gfx Filters: blur */\n" + "#ifdef SHD_FILTER_BLUR\n" + "attribute vec2 filter_data_0;\n" + "attribute vec2 filter_data_1;\n" + "varying vec2 blur_radius;\n" + "varying vec2 blur_divider;\n" + "#endif\n" "void main()\n" "{\n" " gl_Position = mvp * vertex;\n" @@ -350,5 +413,9 @@ static const char vertex_glsl[] = " displace_min = filter_data_1;\n" " displace_max = filter_data_2;\n" "#endif\n" + "#ifdef SHD_FILTER_BLUR\n" + " blur_radius = filter_data_0;\n" + " blur_divider = filter_data_1;\n" + "#endif\n" "}\n"; diff --git a/src/modules/evas/engines/gl_common/shader/fragment.glsl b/src/modules/evas/engines/gl_common/shader/fragment.glsl index d419b14253..7a2b5bd9c1 100644 --- a/src/modules/evas/engines/gl_common/shader/fragment.glsl +++ b/src/modules/evas/engines/gl_common/shader/fragment.glsl @@ -6,6 +6,9 @@ FRAGMENT_SHADER +#define M_PI 3.141592653589793238462643383279502884 +#define M_PI_2 1.570796326794896619231321691639751442 + #ifndef SHD_NOMUL varying vec4 col; #endif @@ -85,12 +88,28 @@ varying vec2 displace_max; uniform sampler2D tex_filter; #endif +#ifdef SHD_FILTER_BLUR +varying vec2 blur_radius; +varying vec2 blur_divider; +#endif + +// ---------------------------------------------------------------------------- + +#ifndef SHD_FILTER_BLUR void main() { #if defined(SHD_EXTERNAL) || defined(SHD_TEX) vec2 coord = tex_c; #endif +#else // SHD_FILTER_BLUR + +vec4 fetch_pixel(float ox, float oy) +{ + vec2 coord = tex_c + vec2(ox, oy); + +#endif // SHD_FILTER_BLUR + vec4 c; #ifdef SHD_FILTER_DISPLACE @@ -205,6 +224,8 @@ void main() new_alpha); #endif +#ifndef SHD_FILTER_BLUR + gl_FragColor = c #ifndef SHD_NOMUL @@ -219,3 +240,51 @@ void main() ; } +#else // SHD_FILTER_BLUR + + return c; +} + +void main() +{ + float x, y, div_x, div_y; + float rx = blur_radius.x; + float ry = blur_radius.y; + vec4 acc = vec4(0.,0.,0.,0.); + vec4 c; + + div_x = blur_divider.x; + div_y = blur_divider.y; + + float diam_x = rx * 2.0 + 1.0; + float diam_y = ry * 2.0 + 1.0; + float div = 0.0; + + // This is completely insane... but renders properly :) + for (y = -ry; y <= ry; y += 1.0) + { + float wy = (y + ry) / (diam_y - 1.0) * 6.0 - 3.0; + wy = (sin(wy + M_PI_2) + 1.0) / 2.0; + + for (x = -rx; x <= rx; x += 1.0) + { + float wx = (x + rx) / (diam_x - 1.0) * 6.0 - 3.0; + wx = (sin(wx + M_PI_2) + 1.0) / 2.0; + + vec4 px = fetch_pixel(x / div_x, y / div_y); + + acc += px * wx * wy; + div += wx * wy; + } + } + + c = acc / div; + +#ifndef SHD_NOMUL + gl_FragColor = c * col; +#else + gl_FragColor = c; +#endif +} + +#endif // SHD_FILTER_BLUR diff --git a/src/modules/evas/engines/gl_common/shader/vertex.glsl b/src/modules/evas/engines/gl_common/shader/vertex.glsl index 1f2746a42e..1f2a1701f8 100644 --- a/src/modules/evas/engines/gl_common/shader/vertex.glsl +++ b/src/modules/evas/engines/gl_common/shader/vertex.glsl @@ -78,6 +78,14 @@ varying vec2 displace_min; varying vec2 displace_max; #endif +/* Gfx Filters: blur */ +#ifdef SHD_FILTER_BLUR +attribute vec2 filter_data_0; +attribute vec2 filter_data_1; +varying vec2 blur_radius; +varying vec2 blur_divider; +#endif + void main() { @@ -157,5 +165,9 @@ void main() displace_min = filter_data_1; displace_max = filter_data_2; #endif -} +#ifdef SHD_FILTER_BLUR + blur_radius = filter_data_0; + blur_divider = filter_data_1; +#endif +} diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 03ef61071d..4b0d38f118 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -3029,7 +3029,7 @@ _gfx_filter_func_get(Evas_Filter_Command *cmd) switch (cmd->mode) { case EVAS_FILTER_MODE_BLEND: funcptr = gl_filter_blend_func_get(cmd); break; - //case EVAS_FILTER_MODE_BLUR: funcptr = gl_filter_blur_func_get(cmd); break; + case EVAS_FILTER_MODE_BLUR: funcptr = gl_filter_blur_func_get(cmd); break; //case EVAS_FILTER_MODE_BUMP: funcptr = gl_filter_bump_func_get(cmd); break; case EVAS_FILTER_MODE_CURVE: funcptr = gl_filter_curve_func_get(cmd); break; case EVAS_FILTER_MODE_DISPLACE: funcptr = gl_filter_displace_func_get(cmd); break; diff --git a/src/modules/evas/engines/gl_generic/filters/gl_engine_filter.h b/src/modules/evas/engines/gl_generic/filters/gl_engine_filter.h index b49180dac4..4d4baca126 100644 --- a/src/modules/evas/engines/gl_generic/filters/gl_engine_filter.h +++ b/src/modules/evas/engines/gl_generic/filters/gl_engine_filter.h @@ -10,7 +10,7 @@ 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); -//GL_Filter_Apply_Func gl_filter_blur_func_get(Evas_Filter_Command *cmd); +GL_Filter_Apply_Func gl_filter_blur_func_get(Evas_Filter_Command *cmd); //GL_Filter_Apply_Func gl_filter_bump_func_get(Evas_Filter_Command *cmd); GL_Filter_Apply_Func gl_filter_curve_func_get(Evas_Filter_Command *cmd); GL_Filter_Apply_Func gl_filter_displace_func_get(Evas_Filter_Command *cmd); 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 new file mode 100644 index 0000000000..12458cb303 --- /dev/null +++ b/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c @@ -0,0 +1,63 @@ +#include "gl_engine_filter.h" + +static Eina_Bool +_gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd) +{ + Evas_Engine_GL_Context *gc; + Evas_GL_Image *image, *surface; + RGBA_Draw_Context *dc_save; + int x, y, w, h; + + 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); + + image = evas_ector_buffer_drawable_image_get(cmd->input->buffer); + EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE); + + surface = evas_ector_buffer_render_image_get(cmd->output->buffer); + EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE); + + evas_gl_common_context_target_surface_set(gc, surface); + + 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); + + if (cmd->input == cmd->output) + gc->dc->render_op = EVAS_RENDER_COPY; + else + gc->dc->render_op = _gfx_to_evas_render_op(cmd->draw.rop); + + DBG("blur %d @%p -> %d @%p", cmd->input->id, cmd->input->buffer, + cmd->output->id, cmd->output->buffer); + + evas_gl_common_filter_blur_push(gc, image->tex, x, y, w, h, + cmd->blur.dx, cmd->blur.dy); + + evas_common_draw_context_free(gc->dc); + gc->dc = dc_save; + + evas_ector_buffer_engine_image_release(cmd->input->buffer, image); + evas_ector_buffer_engine_image_release(cmd->output->buffer, surface); + + DEBUG_TIME_END(); + + return EINA_TRUE; +} + +GL_Filter_Apply_Func +gl_filter_blur_func_get(Evas_Filter_Command *cmd) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL); + + return _gl_filter_blur; +}