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.
This commit is contained in:
Jean-Philippe Andre 2017-01-25 18:06:29 +09:00
parent 125c7d956e
commit 5bce7120f1
12 changed files with 382 additions and 30 deletions

View File

@ -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/evas_ector_gl_image_buffer.c \
modules/evas/engines/gl_generic/filters/gl_engine_filter.h \ 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_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_curve.c \
modules/evas/engines/gl_generic/filters/gl_filter_displace.c \ modules/evas/engines/gl_generic/filters/gl_filter_displace.c \
modules/evas/engines/gl_generic/filters/gl_filter_fill.c \ modules/evas/engines/gl_generic/filters/gl_filter_fill.c \

View File

@ -47,6 +47,8 @@ static const Filter_Image images_anim[] = {
/* builtin filter examples */ /* builtin filter examples */
static const Filter templates[] = { static const Filter templates[] = {
{ "Custom", NULL, NULL }, { "Custom", NULL, NULL },
{ "BLUR",
"blur { 15, color = 'darkblue' }", NULL },
{ "Simple blend", { "Simple blend",
"blend { color = 'darkblue' }", NULL }, "blend { color = 'darkblue' }", NULL },
{ "Black shadow", { "Black shadow",

View File

@ -548,11 +548,6 @@ evas_filter_command_blur_add(Evas_Filter_Context *ctx, void *drawctx,
Eina_Bool override; Eina_Bool override;
DATA32 color; 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(ctx, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(drawctx, 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); out = _filter_buffer_get(ctx, outbuf);
EINA_SAFETY_ON_FALSE_GOTO(out, fail); EINA_SAFETY_ON_FALSE_GOTO(out, fail);
if (in == out) out->dirty = EINA_FALSE;
ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A); ENFN->context_color_get(ENDT, drawctx, &R, &G, &B, &A);
color = ARGB_JOIN(A, R, G, B); color = ARGB_JOIN(A, R, G, B);
if (!color) 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); 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); render_op = ENFN->context_render_op_get(ENDT, drawctx);
override = (render_op == EVAS_RENDER_COPY); override = (render_op == EVAS_RENDER_COPY);

View File

@ -108,7 +108,7 @@ struct _Evas_GL_Program
GLuint mvp, rotation_id; GLuint mvp, rotation_id;
} uniform; } uniform;
struct { struct {
GLuint loc_filter_data[3]; GLint loc_filter_data[3];
Eina_Bool known_locations; Eina_Bool known_locations;
} attribute; } attribute;
GLuint prog; GLuint prog;
@ -245,6 +245,7 @@ enum _Shader_Type {
SHD_MAP, SHD_MAP,
SHD_FILTER_DISPLACE, SHD_FILTER_DISPLACE,
SHD_FILTER_CURVE, SHD_FILTER_CURVE,
SHD_FILTER_BLUR,
SHD_TYPE_LAST 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); 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 dx, double dy);
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

@ -1205,6 +1205,9 @@ error:
#define PIPE_FREE(x) \ #define PIPE_FREE(x) \
do { _pipebuf_free(x); (x) = NULL; } while (0) do { _pipebuf_free(x); (x) = NULL; } while (0)
#define FREE(x) \
do { free(x); (x) = NULL; } while (0)
typedef struct _Pipebuf typedef struct _Pipebuf
{ {
int skipped, alloc; 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.texsam);
PIPE_FREE(gc->pipe[i].array.mask); PIPE_FREE(gc->pipe[i].array.mask);
PIPE_FREE(gc->pipe[i].array.masksam); 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 void
evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc, evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex, Evas_GL_Texture *map_tex, 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 // displace properties
gc->pipe[pn].shader.filter.map_tex = map_tex->pt->texture; gc->pipe[pn].shader.filter.map_tex = map_tex->pt->texture;
gc->pipe[pn].shader.filter.map_nearest = nearest; gc->pipe[pn].shader.filter.map_nearest = nearest;
gc->pipe[pn].array.filter_data_count = 3; _filter_data_prepare(gc, pn, prog, 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);
}
}
sx = x; sx = x;
sy = y; sy = y;
@ -3415,6 +3425,111 @@ evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc,
if (!nomul) if (!nomul)
PUSH_6_COLORS(pn, r, g, b, a); 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); 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.texsam);
PIPE_FREE(gc->pipe[i].array.mask); PIPE_FREE(gc->pipe[i].array.mask);
PIPE_FREE(gc->pipe[i].array.masksam); 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.num = 0;
gc->pipe[i].array.alloc = 0; gc->pipe[i].array.alloc = 0;

View File

@ -42,8 +42,9 @@ typedef enum {
SHADER_FLAG_RGB_A_PAIR = (1 << 20), SHADER_FLAG_RGB_A_PAIR = (1 << 20),
SHADER_FLAG_FILTER_DISPLACE = (1 << 21), SHADER_FLAG_FILTER_DISPLACE = (1 << 21),
SHADER_FLAG_FILTER_CURVE = (1 << 22), SHADER_FLAG_FILTER_CURVE = (1 << 22),
SHADER_FLAG_FILTER_BLUR = (1 << 23),
} Shader_Flag; } Shader_Flag;
#define SHADER_FLAG_COUNT 23 #define SHADER_FLAG_COUNT 24
static const char *_shader_flags[SHADER_FLAG_COUNT] = { static const char *_shader_flags[SHADER_FLAG_COUNT] = {
"TEX", "TEX",
@ -68,7 +69,8 @@ static const char *_shader_flags[SHADER_FLAG_COUNT] = {
"ALPHA", "ALPHA",
"RGB_A_PAIR", "RGB_A_PAIR",
"FILTER_DISPLACE", "FILTER_DISPLACE",
"FILTER_CURVE" "FILTER_CURVE",
"FILTER_BLUR"
}; };
static Eina_Bool compiler_released = EINA_FALSE; 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: case SHD_FILTER_CURVE:
flags |= SHADER_FLAG_FILTER_CURVE; flags |= SHADER_FLAG_FILTER_CURVE;
break; break;
case SHD_FILTER_BLUR:
flags |= SHADER_FLAG_FILTER_BLUR;
break;
default: default:
CRI("Impossible shader type."); CRI("Impossible shader type.");
return 0; return 0;

View File

@ -20,6 +20,8 @@ static const char fragment_glsl[] =
"#else\n" "#else\n"
"# define SAMPLER_EXTERNAL_OES sampler2D\n" "# define SAMPLER_EXTERNAL_OES sampler2D\n"
"#endif\n" "#endif\n"
"#define M_PI 3.141592653589793238462643383279502884\n"
"#define M_PI_2 1.570796326794896619231321691639751442\n"
"#ifndef SHD_NOMUL\n" "#ifndef SHD_NOMUL\n"
"varying vec4 col;\n" "varying vec4 col;\n"
"#endif\n" "#endif\n"
@ -89,11 +91,22 @@ static const char fragment_glsl[] =
"#ifdef SHD_FILTER_CURVE\n" "#ifdef SHD_FILTER_CURVE\n"
"uniform sampler2D tex_filter;\n" "uniform sampler2D tex_filter;\n"
"#endif\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" "void main()\n"
"{\n" "{\n"
"#if defined(SHD_EXTERNAL) || defined(SHD_TEX)\n" "#if defined(SHD_EXTERNAL) || defined(SHD_TEX)\n"
" vec2 coord = tex_c;\n" " vec2 coord = tex_c;\n"
"#endif\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" " vec4 c;\n"
"#ifdef SHD_FILTER_DISPLACE\n" "#ifdef SHD_FILTER_DISPLACE\n"
" vec2 dxy = texture2D(tex_filter, tex_c).rg * displace_vector;\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.g / old_alpha, 0.0)).g * new_alpha,\n"
" texture2D(tex_filter, vec2(c.b / old_alpha, 0.0)).b * new_alpha,\n" " texture2D(tex_filter, vec2(c.b / old_alpha, 0.0)).b * new_alpha,\n"
" new_alpha);\n" " new_alpha);\n"
" //c = vec4(new_alpha, new_alpha, new_alpha, new_alpha);\n"
"#endif\n" "#endif\n"
"#ifndef SHD_FILTER_BLUR\n"
" gl_FragColor =\n" " gl_FragColor =\n"
" c\n" " c\n"
"#ifndef SHD_NOMUL\n" "#ifndef SHD_NOMUL\n"
@ -209,7 +222,50 @@ static const char fragment_glsl[] =
" * fa\n" " * fa\n"
"#endif\n" "#endif\n"
" ;\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[] = static const char vertex_glsl[] =
"/* General-purpose vertex shader for all operations in Evas.\n" "/* 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_min;\n"
"varying vec2 displace_max;\n" "varying vec2 displace_max;\n"
"#endif\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" "void main()\n"
"{\n" "{\n"
" gl_Position = mvp * vertex;\n" " gl_Position = mvp * vertex;\n"
@ -350,5 +413,9 @@ static const char vertex_glsl[] =
" displace_min = filter_data_1;\n" " displace_min = filter_data_1;\n"
" displace_max = filter_data_2;\n" " displace_max = filter_data_2;\n"
"#endif\n" "#endif\n"
"#ifdef SHD_FILTER_BLUR\n"
" blur_radius = filter_data_0;\n"
" blur_divider = filter_data_1;\n"
"#endif\n"
"}\n"; "}\n";

View File

@ -6,6 +6,9 @@
FRAGMENT_SHADER FRAGMENT_SHADER
#define M_PI 3.141592653589793238462643383279502884
#define M_PI_2 1.570796326794896619231321691639751442
#ifndef SHD_NOMUL #ifndef SHD_NOMUL
varying vec4 col; varying vec4 col;
#endif #endif
@ -85,12 +88,28 @@ varying vec2 displace_max;
uniform sampler2D tex_filter; uniform sampler2D tex_filter;
#endif #endif
#ifdef SHD_FILTER_BLUR
varying vec2 blur_radius;
varying vec2 blur_divider;
#endif
// ----------------------------------------------------------------------------
#ifndef SHD_FILTER_BLUR
void main() void main()
{ {
#if defined(SHD_EXTERNAL) || defined(SHD_TEX) #if defined(SHD_EXTERNAL) || defined(SHD_TEX)
vec2 coord = tex_c; vec2 coord = tex_c;
#endif #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; vec4 c;
#ifdef SHD_FILTER_DISPLACE #ifdef SHD_FILTER_DISPLACE
@ -205,6 +224,8 @@ void main()
new_alpha); new_alpha);
#endif #endif
#ifndef SHD_FILTER_BLUR
gl_FragColor = gl_FragColor =
c c
#ifndef SHD_NOMUL #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

View File

@ -78,6 +78,14 @@ varying vec2 displace_min;
varying vec2 displace_max; varying vec2 displace_max;
#endif #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() void main()
{ {
@ -157,5 +165,9 @@ void main()
displace_min = filter_data_1; displace_min = filter_data_1;
displace_max = filter_data_2; displace_max = filter_data_2;
#endif #endif
}
#ifdef SHD_FILTER_BLUR
blur_radius = filter_data_0;
blur_divider = filter_data_1;
#endif
}

View File

@ -3029,7 +3029,7 @@ _gfx_filter_func_get(Evas_Filter_Command *cmd)
switch (cmd->mode) switch (cmd->mode)
{ {
case EVAS_FILTER_MODE_BLEND: funcptr = gl_filter_blend_func_get(cmd); break; 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_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_CURVE: funcptr = gl_filter_curve_func_get(cmd); break;
case EVAS_FILTER_MODE_DISPLACE: funcptr = gl_filter_displace_func_get(cmd); break; case EVAS_FILTER_MODE_DISPLACE: funcptr = gl_filter_displace_func_get(cmd); break;

View File

@ -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); 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_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_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_curve_func_get(Evas_Filter_Command *cmd);
GL_Filter_Apply_Func gl_filter_displace_func_get(Evas_Filter_Command *cmd); GL_Filter_Apply_Func gl_filter_displace_func_get(Evas_Filter_Command *cmd);

View File

@ -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;
}