forked from enlightenment/efl
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:
parent
125c7d956e
commit
5bce7120f1
|
@ -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 \
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue