From 266ee07805be6cc238123b2580a62b7d6f54cd3a Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Mon, 3 Apr 2017 16:29:51 +0900 Subject: evas filters: Add custom fragment shader The objective is to generate GLSL code from C and pass all the required constants directly. This will be used for highly specialized variants of GL blur. --- src/lib/evas/filters/evas_filter.c | 61 ++++++---- .../evas/engines/gl_common/evas_gl_common.h | 6 +- .../evas/engines/gl_common/evas_gl_context.c | 78 +++++++++++++ .../evas/engines/gl_common/evas_gl_shader.c | 48 +++++++- .../engines/gl_common/shader/evas_gl_shaders.x | 23 ++-- .../evas/engines/gl_common/shader/fragment.glsl | 32 +++--- .../engines/gl_generic/filters/gl_filter_blur.c | 128 ++++++++++++++++++++- 7 files changed, 320 insertions(+), 56 deletions(-) diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 270c79f948..7c51a0001a 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -684,6 +684,27 @@ evas_filter_command_fill_add(Evas_Filter_Context *ctx, void *draw_context, return cmd; } +static int +_blur_support_gl(Evas_Filter_Context *ctx, Evas_Filter_Buffer *in, Evas_Filter_Buffer *out, + Evas_Filter_Blur_Type type, int count, int dx, int dy) +{ + Evas_Filter_Command cmd = {}; + + cmd.input = in; + cmd.output = out; + cmd.mode = EVAS_FILTER_MODE_BLUR; + cmd.ctx = ctx; + cmd.blur.count = count; + cmd.blur.type = type; + cmd.blur.dx = dx; + cmd.blur.dy = dy; + + if (cmd.ENFN->gfx_filter_supports(cmd.ENDT, &cmd) != EVAS_FILTER_SUPPORT_GL) + return 0; + + return cmd.draw.need_temp_buffer ? 2 : 1; +} + static Evas_Filter_Command * evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, Evas_Filter_Buffer *in, Evas_Filter_Buffer *out, @@ -694,6 +715,7 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd; Evas_Filter_Buffer *dx_in, *dx_out, *dy_in, *dy_out, *tmp = NULL; double dx, dy; + int passes; /* GL blur implementation: * - Create intermediate buffer T (variable size) @@ -712,15 +734,15 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, dy_out = out; #if 0 - if (type == EVAS_FILTER_BLUR_DEFAULT) + if ((type == EVAS_FILTER_BLUR_DEFAULT) && (rx == ry) && (rx >= 8)) { int down_x = 1, down_y = 1; /* For now, disable scaling - testing perfect gaussian blur until it's * ready: */ - 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); - + //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); + down_x = down_y = 4; tmp = evas_filter_temporary_buffer_get(ctx, ctx->w / down_x, ctx->h / down_y, in->alpha_only, EINA_TRUE); @@ -743,7 +765,19 @@ evas_filter_command_blur_add_gl(Evas_Filter_Context *ctx, } #endif - if (dx && dy) + passes = _blur_support_gl(ctx, in, out, type, count, dx, dy); + if (passes == 1) + { + XDBG("Add GL blur %d -> %d (%.2fx%.2f px)", dx_in->id, dy_out->id, dx, dy); + cmd = _command_new(ctx, EVAS_FILTER_MODE_BLUR, dx_in, NULL, dy_out); + if (!cmd) goto fail; + cmd->blur.type = type; + cmd->blur.dx = dx; + cmd->blur.dy = dy; + cmd->blur.count = count; + dx = dy = 0; + } + else if (dx && dy) { tmp = evas_filter_temporary_buffer_get(ctx, dx_in->w, dx_in->h, in->alpha_only, 1); if (!tmp) goto fail; @@ -798,21 +832,6 @@ fail: return NULL; } -static Eina_Bool -_blur_support_gl(Evas_Filter_Context *ctx, Evas_Filter_Buffer *in, Evas_Filter_Buffer *out) -{ - Evas_Filter_Command cmd = {}; - - cmd.input = in; - cmd.output = out; - cmd.mode = EVAS_FILTER_MODE_BLUR; - cmd.ctx = ctx; - cmd.blur.type = EVAS_FILTER_BLUR_GAUSSIAN; - cmd.blur.dx = 5; - - return cmd.ENFN->gfx_filter_supports(cmd.ENDT, &cmd) == EVAS_FILTER_SUPPORT_GL; -} - Evas_Filter_Command * evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, int inbuf, int outbuf, Evas_Filter_Blur_Type type, @@ -851,7 +870,7 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx, return _command_new(ctx, EVAS_FILTER_MODE_SKIP, NULL, NULL, NULL); } - if (_blur_support_gl(ctx, in, out)) + if (_blur_support_gl(ctx, in, out, type, count, dx, dy)) return evas_filter_command_blur_add_gl(ctx, in, out, type, dx, dy, ox, oy, count, R, G, B, A); // Note (SW engine): 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 ad5835d1ba..258b0d9485 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -265,7 +265,8 @@ enum _Shader_Type { SHD_FILTER_DISPLACE, SHD_FILTER_CURVE, SHD_FILTER_BLUR_X, - SHD_FILTER_BLUR_Y + SHD_FILTER_BLUR_Y, + SHD_FILTER_CUSTOM, }; #define ARRAY_BUFFER_USE 500 @@ -674,6 +675,8 @@ void evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc, E 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, const double * const values, const double * const offsets, int count, double radius, Eina_Bool horiz); +void evas_gl_common_filter_custom_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, const char *fragment_main); int evas_gl_common_shader_program_init(Evas_GL_Shared *shared); void evas_gl_common_shader_program_shutdown(Evas_GL_Shared *shared); @@ -689,6 +692,7 @@ Evas_GL_Program *evas_gl_common_shader_program_get(Evas_Engine_GL_Context *gc, Eina_Bool mask_color, int mw, int mh, Shader_Sampling *psam, int *pnomul, Shader_Sampling *pmasksam); +Evas_GL_Program *evas_gl_common_shader_program_custom_get(Evas_Engine_GL_Context *gc, const char *fragment_main); void evas_gl_common_shader_textures_bind(Evas_GL_Program *p); Eina_Bool evas_gl_common_file_cache_is_dir(const char *file); 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 b61cc6aa9f..66ae821ecf 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -3616,6 +3616,84 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, PUSH_6_COLORS(pn, r, g, b, a); } +void +evas_gl_common_filter_custom_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, + const char *fragment_main) +{ + double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph; + GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4; + GLfloat offsetx, offsety; + Evas_GL_Program *prog; + Eina_Bool blend = EINA_TRUE; + Eina_Bool smooth = EINA_TRUE; + Shader_Type type = SHD_FILTER_CUSTOM; + int pn; + + if (gc->dc->render_op == EVAS_RENDER_COPY) + blend = EINA_FALSE; + + prog = evas_gl_common_shader_program_custom_get(gc, fragment_main); + + pw = tex->pt->w; + ph = tex->pt->h; + pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog, + sx, sy, dw, dh, blend, smooth, + 0, 0, 0, 0, 0, EINA_FALSE); + + gc->pipe[pn].region.type = type; + 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 = 0; + 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, dx, dy, dw, dh); + PIPE_GROW(gc, pn, 6); + + 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, dx, dy, dw, dh); + PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4); +} + // ---------------------------------------------------------------------------- EAPI void 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 29c68ddb21..58f246b34c 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_shader.c +++ b/src/modules/evas/engines/gl_common/evas_gl_shader.c @@ -417,13 +417,16 @@ _shaders_hash_free_cb(void *data) } static char * -evas_gl_common_shader_glsl_get(unsigned int flags, const char *base) +evas_gl_common_shader_glsl_get(unsigned int flags, const char *base, + const char *custom_header) { Eina_Strbuf *s = eina_strbuf_new(); unsigned int k; char *str; - //eina_strbuf_append_printf(s, "#version 300 es\n"); + if (custom_header) + eina_strbuf_append_printf(s, "%s\n", custom_header); + for (k = 0; k < SHADER_FLAG_COUNT; k++) { if (flags & (1 << k)) @@ -576,8 +579,8 @@ evas_gl_common_shader_generate_and_compile(Evas_GL_Shared *shared, unsigned int if (eina_hash_find(shared->shaders_hash, &flags)) return NULL; - vertex = evas_gl_common_shader_glsl_get(flags, vertex_glsl); - fragment = evas_gl_common_shader_glsl_get(flags, fragment_glsl); + vertex = evas_gl_common_shader_glsl_get(flags, vertex_glsl, NULL); + fragment = evas_gl_common_shader_glsl_get(flags, fragment_glsl, NULL); p = evas_gl_common_shader_compile(flags, vertex, fragment); if (p) @@ -976,3 +979,40 @@ end: p->hitcount++; return p; } + +Evas_GL_Program * +evas_gl_common_shader_program_custom_get(Evas_Engine_GL_Context *gc, + const char *fragment_main) +{ + char *vertex, *fragment; + unsigned int flags; + Evas_GL_Program *p; + + // FIXME + static Eina_Hash *hash = 0; + if (!hash) hash = eina_hash_string_superfast_new(NULL); + + p = eina_hash_find(hash, fragment_main); + if (p) return p; + + flags = SHADER_FLAG_TEX | SHADER_FLAG_IMG | SHADER_FLAG_NOMUL; + if (gc->shared->info.bgra) flags |= SHADER_FLAG_BGRA; + + vertex = evas_gl_common_shader_glsl_get(flags, vertex_glsl, NULL); + fragment = evas_gl_common_shader_glsl_get(flags, fragment_glsl, fragment_main); + + p = evas_gl_common_shader_compile(flags, vertex, fragment); + if (p) + { + p->uniform.mvp = glGetUniformLocation(p->prog, "mvp"); + p->uniform.rotation_id = glGetUniformLocation(p->prog, "rotation_id"); + evas_gl_common_shader_textures_bind(p); + eina_hash_add(hash, fragment_main, p); + } + else WRN("Failed to compile custom shader (flags: %08x):\n%s", flags, fragment_main); + + free(vertex); + free(fragment); + + return p; +} 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 879548b184..628a2d190f 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 @@ -98,17 +98,11 @@ static const char fragment_glsl[] = "uniform float blur_div;\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" + "#if defined(SHD_EXTERNAL) || defined(SHD_TEX)\n" " vec2 coord = tex_c + vec2(ox, oy);\n" - "#endif // SHD_FILTER_BLUR\n" + "#endif\n" " vec4 c;\n" "#ifdef SHD_FILTER_DISPLACE\n" " vec2 dxy = texture2D(tex_filter, tex_c).rg * displace_vector;\n" @@ -211,8 +205,7 @@ static const char fragment_glsl[] = " texture2D(tex_filter, vec2(c.b / old_alpha, 0.0)).b * new_alpha,\n" " new_alpha);\n" "#endif\n" - "#ifndef SHD_FILTER_BLUR\n" - " gl_FragColor =\n" + " return\n" " c\n" "#ifndef SHD_NOMUL\n" " * col\n" @@ -225,9 +218,15 @@ static const char fragment_glsl[] = "#endif\n" " ;\n" "}\n" - "#else // SHD_FILTER_BLUR\n" - " return c;\n" + "#if defined(FRAGMENT_MAIN)\n" + "FRAGMENT_MAIN\n" + "#elif !defined(SHD_FILTER_BLUR)\n" + "void main()\n" + "{\n" + " gl_FragColor = fetch_pixel(0.0, 0.0);\n" "}\n" + "// ----------------------------------------------------------------------------\n" + "#else\n" "#ifndef SHD_FILTER_DIR_Y\n" "# define FETCH_PIXEL(x) fetch_pixel((x), 0.0)\n" "#else\n" diff --git a/src/modules/evas/engines/gl_common/shader/fragment.glsl b/src/modules/evas/engines/gl_common/shader/fragment.glsl index 4a710f595c..b968ae14ad 100644 --- a/src/modules/evas/engines/gl_common/shader/fragment.glsl +++ b/src/modules/evas/engines/gl_common/shader/fragment.glsl @@ -97,20 +97,11 @@ uniform float blur_div; // ---------------------------------------------------------------------------- -#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) { +#if defined(SHD_EXTERNAL) || defined(SHD_TEX) vec2 coord = tex_c + vec2(ox, oy); - -#endif // SHD_FILTER_BLUR +#endif vec4 c; @@ -226,9 +217,7 @@ vec4 fetch_pixel(float ox, float oy) new_alpha); #endif -#ifndef SHD_FILTER_BLUR - - gl_FragColor = + return c #ifndef SHD_NOMUL * col @@ -242,11 +231,22 @@ vec4 fetch_pixel(float ox, float oy) ; } -#else // SHD_FILTER_BLUR - return c; +#if defined(FRAGMENT_MAIN) + +FRAGMENT_MAIN + +#elif !defined(SHD_FILTER_BLUR) + +void main() +{ + gl_FragColor = fetch_pixel(0.0, 0.0); } + +// ---------------------------------------------------------------------------- +#else + #ifndef SHD_FILTER_DIR_Y # define FETCH_PIXEL(x) fetch_pixel((x), 0.0) #else 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 8c78f8c196..59eab4ba29 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 @@ -246,15 +246,139 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd) return EINA_TRUE; } +static Eina_Bool +_gl_filter_blur_2d_radius_2(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd) +{ + Evas_Engine_GL_Context *gc; + Evas_GL_Image *image, *surface; + RGBA_Draw_Context *dc_save; + double sx, sy, sw, sh, ssx, ssy, ssw, ssh, dx, dy, dw, dh; + double s_w, s_h, d_w, d_h; + Eina_Rectangle s_region[4], d_region[4]; + int nx, ny, nw, nh, regions; + const char *fragment_main; + Eina_Strbuf *str; + + static char *base_code = NULL; + + if (!base_code) + { + const char *code; + + code = "const float wei = 1.0;\n" + "const float off = 1.0/3.0;\n" + "\n" + "void main ()\n" + "{\n" + " vec4 px1, px2, px3, px4;\n" + " px1 = fetch_pixel(-off / W, -off / H);\n" + " px2 = fetch_pixel(-off / W, off / H);\n" + " px3 = fetch_pixel( off / W, -off / H);\n" + " px4 = fetch_pixel( off / W, off / H);\n" + " gl_FragColor = (px1 + px2 + px3 + px4) / 4.0;\n" + "}\n"; + + str = eina_strbuf_new(); + eina_strbuf_append(str, "#define FRAGMENT_MAIN\n"); + eina_strbuf_append(str, code); + eina_strbuf_replace_all(str, "\n", " \\\n"); + base_code = eina_strbuf_string_steal(str); + eina_strbuf_free(str); + } + + DEBUG_TIME_BEGIN(); + + s_w = cmd->input->w; + s_h = cmd->input->h; + d_w = cmd->output->w; + d_h = cmd->output->h; + EINA_SAFETY_ON_FALSE_RETURN_VAL(s_w && s_h && d_w && d_h, EINA_FALSE); + + 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); + + DBG("blur %d @%p -> %d @%p (custom 2D)", + cmd->input->id, cmd->input->buffer, + cmd->output->id, cmd->output->buffer); + + dc_save = gc->dc; + gc->dc = evas_common_draw_context_new(); + gc->dc->render_op = _gfx_to_evas_render_op(cmd->draw.rop); + + // Set constants in shader code + str = eina_strbuf_new(); + eina_strbuf_append_printf(str, "const float W = %f;\n", (float) image->tex->pt->w); + eina_strbuf_append_printf(str, "const float H = %f;\n", (float) image->tex->pt->h); + eina_strbuf_append(str, base_code); + fragment_main = eina_strbuf_string_get(str); + + // FIXME: Implement region support! (note: can't separate perfectly in 2d) + regions = 1; + s_region[0] = S_RECT(0, 0, s_w, s_h); + d_region[0] = D_RECT(0, 0, d_w, d_h); + + for (int k = 0; k < regions; k++) + { + sx = s_region[k].x; + sy = s_region[k].y; + sw = s_region[k].w; + sh = s_region[k].h; + + dx = d_region[k].x + cmd->draw.ox; + dy = d_region[k].y + cmd->draw.oy; + dw = d_region[k].w; + dh = d_region[k].h; + + nx = dx; ny = dy; nw = dw; nh = dh; + RECTS_CLIP_TO_RECT(nx, ny, nw, nh, 0, 0, d_w, d_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_custom_push(gc, image->tex, ssx, ssy, ssw, ssh, + dx, dy, dw, dh, fragment_main); + } + eina_strbuf_free(str); + + 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(Render_Engine_GL_Generic *re EINA_UNUSED, 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); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!cmd->blur.dx && !cmd->blur.dy, NULL); - // 1D blurs only, radius != 0 - EINA_SAFETY_ON_FALSE_RETURN_VAL((!cmd->blur.dx) ^ (!cmd->blur.dy), NULL); + // FIXME: Handle box blur, perfect gaussian, scaling and other special cases + + if ((EINA_FLT_EQ(cmd->blur.dx, cmd->blur.dy)) && (cmd->output != cmd->input)) + { + // Special cases for very fast blurs + double r = cmd->blur.dx; + + if (EINA_FLT_EQ(r, 2.0)) + return _gl_filter_blur_2d_radius_2; + } + cmd->draw.need_temp_buffer = EINA_TRUE; return _gl_filter_blur; } -- cgit v1.2.1