evas filters: Implement displace filter in pure GL

This one was a bit more... "fun". I had to add a new vertex
attribute and obviously using a VertexAttribPointer led to
incomprehensible crashes. But a simple glVertexAttrib2fv makes
it work like a charm!

A rare option is not handled yet.
This commit is contained in:
Jean-Philippe Andre 2017-01-24 15:28:18 +09:00
parent ac8812665b
commit 125c7d956e
12 changed files with 684 additions and 51 deletions

View File

@ -844,6 +844,8 @@ 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_curve.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_mask.c \
$(NULL)

View File

@ -433,6 +433,11 @@ _command_new(Evas_Filter_Context *ctx, Evas_Filter_Mode mode,
cmd->input = input;
cmd->mask = mask;
cmd->output = output;
cmd->draw.R = 255;
cmd->draw.G = 255;
cmd->draw.B = 255;
cmd->draw.A = 255;
cmd->draw.rop = EFL_GFX_RENDER_OP_BLEND;
if (output) output->dirty = EINA_TRUE;
ctx->commands = eina_inlist_append(ctx->commands, EINA_INLIST_GET(cmd));
@ -1001,7 +1006,10 @@ evas_filter_command_curve_add(Evas_Filter_Context *ctx,
memcpy(copy, curve, 256 * sizeof(DATA8));
cmd->curve.data = copy;
cmd->curve.channel = channel;
if (cmd->input->alpha_only)
cmd->curve.channel = EVAS_FILTER_CHANNEL_ALPHA;
else
cmd->curve.channel = channel;
return cmd;
}

View File

@ -107,6 +107,10 @@ struct _Evas_GL_Program
struct {
GLuint mvp, rotation_id;
} uniform;
struct {
GLuint loc_filter_data[3];
Eina_Bool known_locations;
} attribute;
GLuint prog;
Eina_Bool reset : 1;
@ -239,6 +243,8 @@ enum _Shader_Type {
SHD_NV12_709,
SHD_RGB_A_PAIR,
SHD_MAP,
SHD_FILTER_DISPLACE,
SHD_FILTER_CURVE,
SHD_TYPE_LAST
};
@ -268,6 +274,7 @@ struct _Evas_Engine_GL_Context
Eina_Bool blend : 2;
Eina_Bool clip : 2;
Eina_Bool anti_alias : 2;
Eina_Bool has_filter_data : 1;
} current;
} state;
@ -300,6 +307,11 @@ struct _Evas_Engine_GL_Context
Eina_Bool blend : 2;
Eina_Bool mask_smooth : 2;
Eina_Bool clip : 2;
struct {
GLuint map_tex;
Eina_Bool map_nearest : 1;
Eina_Bool map_delete : 1;
} filter;
} shader;
struct {
int num, alloc;
@ -312,6 +324,8 @@ struct _Evas_Engine_GL_Context
GLfloat *texsam;
GLfloat *mask;
GLfloat *masksam;
int filter_data_count; // number of vec2
GLfloat *filter_data;
Evas_GL_Image *im;
GLuint buffer;
int buffer_alloc;
@ -631,6 +645,12 @@ void evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *g
Eina_Bool tex_only,
Evas_Colorspace cspace);
// Gfx Filters
void evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc, Evas_GL_Texture *tex, Evas_GL_Texture *map_tex,
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);
int evas_gl_common_shader_program_init(Evas_GL_Shared *shared);
void evas_gl_common_shader_program_shutdown(Evas_GL_Shared *shared);
EAPI void evas_gl_common_shaders_flush(Evas_GL_Shared *shared);

View File

@ -1380,6 +1380,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);
}
}
@ -3117,6 +3118,309 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,
}
}
// ----------------------------------------------------------------------------
// Gfx Filters
static inline void
_filter_data_flush(Evas_Engine_GL_Context *gc, Evas_GL_Program *prog)
{
// filter_data is not using a vertex array, which means early flushes
// are necessary. Vertex arrays crashed for whatever reason :(
for (size_t k = 0; k < MAX_PIPES; k++)
if ((gc->pipe[k].array.filter_data || gc->pipe[k].shader.filter.map_tex)
&& (gc->pipe[k].shader.prog == prog))
{
shader_array_flush(gc);
break;
}
}
void
evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex, Evas_GL_Texture *map_tex,
int x, int y, int w, int h, double dx, double dy,
Eina_Bool nearest)
{
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;
Shader_Sampling sam = SHD_SAM11;
GLfloat offsetx, offsety;
GLfloat *filter_data;
int r, g, b, a, nomul = 0, pn;
Evas_GL_Program *prog;
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_DISPLACE, NULL, 0, r, g, b, a,
w, h, w, h, smooth, tex, EINA_FALSE,
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
&sam, &nomul, NULL);
_filter_data_flush(gc, prog);
pn = _evas_gl_common_context_push(SHD_FILTER_DISPLACE, gc, tex, NULL, prog,
x, y, w, h, blend, smooth,
0, 0, 0, 0, 0, EINA_FALSE);
gc->pipe[pn].region.type = SHD_FILTER_DISPLACE;
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 = (sam != SHD_SAM11);
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);
// 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);
}
}
sx = x;
sy = y;
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 (sam)
{
double samx = (double)(sw) / (double)(tex->pt->w * w * 4);
double samy = (double)(sh) / (double)(tex->pt->h * h * 4);
PUSH_SAMPLES(pn, samx, samy);
}
filter_data = gc->pipe[pn].array.filter_data;
filter_data[0] = (dx * tex->w / pw) / w;
filter_data[1] = (dy * tex->h / ph) / h;
filter_data[2] = tex->x / pw;
filter_data[3] = tex->y / ph;
filter_data[4] = (tex->x + tex->w) / pw;
filter_data[5] = (tex->y + tex->h) / ph;
if (!nomul)
PUSH_6_COLORS(pn, r, g, b, a);
}
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)
{
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;
Shader_Sampling sam = SHD_SAM11;
GLfloat offsetx, offsety;
int r, g, b, a, nomul = 0, pn, k;
uint32_t values[256];
Evas_GL_Program *prog;
Eina_Bool blend = EINA_TRUE;
Eina_Bool smooth = EINA_TRUE;
GLuint map_tex;
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_CURVE, NULL, 0, r, g, b, a,
w, h, w, h, smooth, tex, EINA_FALSE,
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
&sam, &nomul, NULL);
_filter_data_flush(gc, prog);
pn = _evas_gl_common_context_push(SHD_FILTER_CURVE, gc, tex, NULL, prog,
x, y, w, h, blend, smooth,
0, 0, 0, 0, 0, EINA_FALSE);
gc->pipe[pn].region.type = SHD_FILTER_CURVE;
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 = (sam != SHD_SAM11);
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);
// Build 256 colors map in RGBA
switch (channel)
{
case 0: // EVAS_FILTER_CHANNEL_ALPHA
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(points[k], k, k, k);
break;
case 1: // EVAS_FILTER_CHANNEL_RED
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(k, points[k], k, k);
break;
case 2: // EVAS_FILTER_CHANNEL_GREEN
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(k, k, points[k], k);
break;
case 3: // EVAS_FILTER_CHANNEL_BLUE
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(k, k, k, points[k]);
break;
case 4: // EVAS_FILTER_CHANNEL_RGB
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(k, points[k], points[k], points[k]);
break;
case 5: // ALPHA only
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(points[k], points[k], points[k], points[k]);
break;
default: // INVALID: no curve applied
for (k = 0; k < 256; k++)
values[k] = ARGB_JOIN(k, k, k, k);
break;
}
// Synchronous upload of 256x1 RGBA texture (FIXME: no reuse)
glGenTextures(1, &map_tex);
glBindTexture(GL_TEXTURE_2D, map_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, values);
// Set curve properties (no need for filter_data)
gc->pipe[pn].shader.filter.map_tex = map_tex;
gc->pipe[pn].shader.filter.map_nearest = EINA_TRUE;
gc->pipe[pn].shader.filter.map_delete = EINA_TRUE;
gc->pipe[pn].array.filter_data_count = 0;
sx = x;
sy = y;
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 (sam)
{
double samx = (double)(sw) / (double)(tex->pt->w * w * 4);
double samy = (double)(sh) / (double)(tex->pt->h * h * 4);
PUSH_SAMPLES(pn, samx, samy);
}
if (!nomul)
PUSH_6_COLORS(pn, r, g, b, a);
shader_array_flush(gc);
}
// ----------------------------------------------------------------------------
EAPI void
evas_gl_common_context_flush(Evas_Engine_GL_Context *gc)
{
@ -3454,7 +3758,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
unsigned char *texsam_ptr = NULL;
unsigned char *mask_ptr = NULL;
unsigned char *masksam_ptr = NULL;
GLint MASK_TEXTURE = GL_TEXTURE0;
GLint ACTIVE_TEXTURE = GL_TEXTURE0;
if (glsym_glMapBuffer && glsym_glUnmapBuffer)
{
@ -3576,7 +3880,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
{
glEnableVertexAttribArray(SHAD_MASK);
glVertexAttribPointer(SHAD_MASK, MASK_CNT, GL_FLOAT, GL_FALSE, 0, mask_ptr);
glActiveTexture(MASK_TEXTURE);
glActiveTexture(ACTIVE_TEXTURE);
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texm);
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
if (shared->info.anisotropic > 0.0)
@ -3618,7 +3922,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glEnableVertexAttribArray(SHAD_TEXUV);
glVertexAttribPointer(SHAD_TEXUV, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texuv_ptr);
MASK_TEXTURE += 1;
ACTIVE_TEXTURE += 1;
}
else
{
@ -3650,7 +3954,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
MASK_TEXTURE += 1;
ACTIVE_TEXTURE += 1;
}
else
{
@ -3697,7 +4001,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
MASK_TEXTURE += 2;
ACTIVE_TEXTURE += 2;
}
else if (gc->pipe[i].array.use_texuv2)
{
@ -3728,7 +4032,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glActiveTexture(GL_TEXTURE0);
glDisableVertexAttribArray(SHAD_TEXUV3);
MASK_TEXTURE += 1;
ACTIVE_TEXTURE += 1;
}
else
{
@ -3741,7 +4045,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
{
glEnableVertexAttribArray(SHAD_MASK);
glVertexAttribPointer(SHAD_MASK, MASK_CNT, GL_FLOAT, GL_FALSE, 0, mask_ptr);
glActiveTexture(MASK_TEXTURE);
glActiveTexture(ACTIVE_TEXTURE);
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texm);
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
if (shared->info.anisotropic > 0.0)
@ -3767,6 +4071,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glVertexAttribPointer(SHAD_MASKSAM, SAM_CNT, GL_FLOAT, GL_FALSE, 0, masksam_ptr);
}
else glDisableVertexAttribArray(SHAD_MASKSAM);
ACTIVE_TEXTURE += 1;
}
else
{
@ -3774,10 +4079,38 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
glDisableVertexAttribArray(SHAD_MASKSAM);
}
/* Gfx filters: data */
if (gc->pipe[i].array.filter_data)
{
for (int k = 0; k < gc->pipe[i].array.filter_data_count; k++)
glVertexAttrib2fv(prog->attribute.loc_filter_data[k], &gc->pipe[i].array.filter_data[k * 2]);
}
/* Gfx filters: texture (or data array as texture) */
if (gc->pipe[i].shader.filter.map_tex)
{
glActiveTexture(ACTIVE_TEXTURE);
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.filter.map_tex);
if (gc->pipe[i].shader.filter.map_nearest)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
ACTIVE_TEXTURE += 1;
}
if (dbgflushnum == 1)
{
const char *types[] =
{ "----", "RECT", "IMAG", "FONT", "YUV-", "YUY2", "NV12", "LINE", "PAIR", "EXTR", "MAP-" };
{ "----", "RECT", "IMAG", "FONT", "YUV-", "YUY2", "NV12", "LINE", "PAIR", "EXTR", "MAP-", "FILTER_DISPLACE" };
printf(" DRAW#%3i %4i -> %p[%4ix%4i] @ %4ix%4i -{ tex %4i type %s }-\n",
i,
gc->pipe[i].array.num / 6,
@ -3818,6 +4151,13 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
gc->state.current.clip = gc->pipe[i].shader.clip;
gc->state.current.anti_alias = gc->pipe[i].array.anti_alias;
if (gc->pipe[i].shader.filter.map_delete)
{
glDeleteTextures(1, &gc->pipe[i].shader.filter.map_tex);
gc->pipe[i].shader.filter.map_delete = EINA_FALSE;
gc->pipe[i].shader.filter.map_tex = 0;
}
gc->pipe[i].array.line = 0;
//gc->pipe[i].array.use_vertex = 0;
gc->pipe[i].array.use_color = 0;
@ -3829,6 +4169,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
gc->pipe[i].array.use_mask = 0;
gc->pipe[i].array.use_masksam = 0;
gc->pipe[i].array.anti_alias = 0;
gc->pipe[i].array.filter_data_count = 0;
PIPE_FREE(gc->pipe[i].array.vertex);
PIPE_FREE(gc->pipe[i].array.color);
@ -3839,6 +4180,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);
gc->pipe[i].array.num = 0;
gc->pipe[i].array.alloc = 0;

View File

@ -40,8 +40,10 @@ typedef enum {
SHADER_FLAG_NOMUL = (1 << 18),
SHADER_FLAG_ALPHA = (1 << 19),
SHADER_FLAG_RGB_A_PAIR = (1 << 20),
SHADER_FLAG_FILTER_DISPLACE = (1 << 21),
SHADER_FLAG_FILTER_CURVE = (1 << 22),
} Shader_Flag;
#define SHADER_FLAG_COUNT 21
#define SHADER_FLAG_COUNT 23
static const char *_shader_flags[SHADER_FLAG_COUNT] = {
"TEX",
@ -64,7 +66,9 @@ static const char *_shader_flags[SHADER_FLAG_COUNT] = {
"AFILL",
"NOMUL",
"ALPHA",
"RGB_A_PAIR"
"RGB_A_PAIR",
"FILTER_DISPLACE",
"FILTER_CURVE"
};
static Eina_Bool compiler_released = EINA_FALSE;
@ -95,6 +99,20 @@ gl_compile_link_error(GLuint target, const char *action, Eina_Bool is_shader)
}
}
static inline void
_attributes_bind(GLint prg)
{
glBindAttribLocation(prg, SHAD_VERTEX, "vertex");
glBindAttribLocation(prg, SHAD_COLOR, "color");
glBindAttribLocation(prg, SHAD_TEXUV, "tex_coord");
glBindAttribLocation(prg, SHAD_TEXUV2, "tex_coord2");
glBindAttribLocation(prg, SHAD_TEXUV3, "tex_coord3");
glBindAttribLocation(prg, SHAD_TEXA, "tex_coorda");
glBindAttribLocation(prg, SHAD_TEXSAM, "tex_sample");
glBindAttribLocation(prg, SHAD_MASK, "mask_coord");
glBindAttribLocation(prg, SHAD_MASKSAM, "tex_masksample");
}
static Evas_GL_Program *
_evas_gl_common_shader_program_binary_load(Eet_File *ef, unsigned int flags)
{
@ -138,15 +156,7 @@ _evas_gl_common_shader_program_binary_load(Eet_File *ef, unsigned int flags)
#endif
glsym_glProgramBinary(prg, formats[0], data, length);
glBindAttribLocation(prg, SHAD_VERTEX, "vertex");
glBindAttribLocation(prg, SHAD_COLOR, "color");
glBindAttribLocation(prg, SHAD_TEXUV, "tex_coord");
glBindAttribLocation(prg, SHAD_TEXUV2, "tex_coord2");
glBindAttribLocation(prg, SHAD_TEXUV3, "tex_coord3");
glBindAttribLocation(prg, SHAD_TEXA, "tex_coorda");
glBindAttribLocation(prg, SHAD_TEXSAM, "tex_sample");
glBindAttribLocation(prg, SHAD_MASK, "mask_coord");
glBindAttribLocation(prg, SHAD_MASKSAM, "tex_masksample");
_attributes_bind(prg);
glGetProgramiv(prg, GL_LINK_STATUS, &ok);
if (!ok)
@ -403,6 +413,7 @@ evas_gl_common_shader_glsl_get(unsigned int flags, const char *base)
unsigned int k;
char *str;
//eina_strbuf_append_printf(s, "#version 300 es\n");
for (k = 0; k < SHADER_FLAG_COUNT; k++)
{
if (flags & (1 << k))
@ -460,15 +471,7 @@ evas_gl_common_shader_compile(unsigned int flags, const char *vertex,
glAttachShader(prg, vtx);
glAttachShader(prg, frg);
glBindAttribLocation(prg, SHAD_VERTEX, "vertex");
glBindAttribLocation(prg, SHAD_COLOR, "color");
glBindAttribLocation(prg, SHAD_TEXUV, "tex_coord");
glBindAttribLocation(prg, SHAD_TEXUV2, "tex_coord2");
glBindAttribLocation(prg, SHAD_TEXUV3, "tex_coord3");
glBindAttribLocation(prg, SHAD_TEXA, "tex_coorda");
glBindAttribLocation(prg, SHAD_TEXSAM, "tex_sample");
glBindAttribLocation(prg, SHAD_MASK, "mask_coord");
glBindAttribLocation(prg, SHAD_MASKSAM, "tex_masksample");
_attributes_bind(prg);
glLinkProgram(prg);
glGetProgramiv(prg, GL_LINK_STATUS, &ok);
@ -776,6 +779,12 @@ evas_gl_common_shader_flags_get(Evas_GL_Shared *shared, Shader_Type type,
case SHD_RGB_A_PAIR:
case SHD_MAP:
break;
case SHD_FILTER_DISPLACE:
flags |= SHADER_FLAG_FILTER_DISPLACE;
break;
case SHD_FILTER_CURVE:
flags |= SHADER_FLAG_FILTER_CURVE;
break;
default:
CRI("Impossible shader type.");
return 0;
@ -847,6 +856,7 @@ evas_gl_common_shader_textures_bind(Evas_GL_Program *p)
{ "texu", 0 },
{ "texv", 0 },
{ "texuv", 0 },
{ "tex_filter", 0 },
{ NULL, 0 }
};
Eina_Bool hastex = 0;
@ -881,6 +891,12 @@ evas_gl_common_shader_textures_bind(Evas_GL_Program *p)
textures[5].enabled = 1;
hastex = 1;
}
if ((p->flags & SHADER_FLAG_FILTER_DISPLACE) ||
(p->flags & SHADER_FLAG_FILTER_CURVE))
{
textures[6].enabled = 1;
hastex = 1;
}
if (hastex)
{

View File

@ -80,9 +80,26 @@ static const char fragment_glsl[] =
"# endif\n"
"# endif\n"
"#endif\n"
"#ifdef SHD_FILTER_DISPLACE\n"
"uniform sampler2D tex_filter;\n"
"varying vec2 displace_vector;\n"
"varying vec2 displace_min;\n"
"varying vec2 displace_max;\n"
"#endif\n"
"#ifdef SHD_FILTER_CURVE\n"
"uniform sampler2D tex_filter;\n"
"#endif\n"
"void main()\n"
"{\n"
"#if defined(SHD_EXTERNAL) || defined(SHD_TEX)\n"
" vec2 coord = tex_c;\n"
"#endif\n"
" vec4 c;\n"
"#ifdef SHD_FILTER_DISPLACE\n"
" vec2 dxy = texture2D(tex_filter, tex_c).rg * displace_vector;\n"
" float fa = texture2D(tex_filter, tex_c).a;\n"
" coord = clamp(tex_c + dxy, displace_min, displace_max);\n"
"#endif\n"
"#if defined(SHD_YUV) || defined(SHD_NV12) || defined(SHD_YUY2)\n"
" float r, g, b, y, u, v, vmu;\n"
"# if defined(SHD_YUV)\n"
@ -116,17 +133,17 @@ static const char fragment_glsl[] =
" b = y + u;\n"
" c = vec4(r, g, b, 1.0);\n"
"#elif defined(SHD_SAM12) || defined(SHD_SAM21)\n"
" vec4 col00 = texture2D(tex, tex_c + tex_s[0]).SWZ;\n"
" vec4 col01 = texture2D(tex, tex_c + tex_s[1]).SWZ;\n"
" vec4 col00 = texture2D(tex, coord + tex_s[0]).SWZ;\n"
" vec4 col01 = texture2D(tex, coord + tex_s[1]).SWZ;\n"
" c = (col00 + col01) / div_s;\n"
"#elif defined(SHD_SAM22)\n"
" vec4 col00 = texture2D(tex, tex_c + tex_s[0]).SWZ;\n"
" vec4 col01 = texture2D(tex, tex_c + tex_s[1]).SWZ;\n"
" vec4 col10 = texture2D(tex, tex_c + tex_s[2]).SWZ;\n"
" vec4 col11 = texture2D(tex, tex_c + tex_s[3]).SWZ;\n"
" vec4 col00 = texture2D(tex, coord + tex_s[0]).SWZ;\n"
" vec4 col01 = texture2D(tex, coord + tex_s[1]).SWZ;\n"
" vec4 col10 = texture2D(tex, coord + tex_s[2]).SWZ;\n"
" vec4 col11 = texture2D(tex, coord + tex_s[3]).SWZ;\n"
" c = (col00 + col01 + col10 + col11) / div_s;\n"
"#elif defined(SHD_TEX) || defined(SHD_EXTERNAL)\n"
" c = texture2D(tex, tex_c).SWZ;\n"
" c = texture2D(tex, coord).SWZ;\n"
"#else\n"
" c = vec4(1, 1, 1, 1);\n"
"#endif\n"
@ -168,6 +185,18 @@ static const char fragment_glsl[] =
"#ifdef SHD_AFILL\n"
" c.a = 1.0;\n"
"#endif\n"
"#ifdef SHD_TEXA\n"
" c *= texture2D(texa, tex_a).r;\n"
"#endif\n"
"#if defined(SHD_FILTER_CURVE)\n"
" float old_alpha = max(c.a, 0.00001);\n"
" float new_alpha = texture2D(tex_filter, vec2(old_alpha, 0.0)).a;\n"
" c = vec4(texture2D(tex_filter, vec2(c.r / old_alpha, 0.0)).r * 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"
" new_alpha);\n"
" //c = vec4(new_alpha, new_alpha, new_alpha, new_alpha);\n"
"#endif\n"
" gl_FragColor =\n"
" c\n"
"#ifndef SHD_NOMUL\n"
@ -176,8 +205,8 @@ static const char fragment_glsl[] =
"#ifdef SHD_MASK\n"
" * ma\n"
"#endif\n"
"#ifdef SHD_TEXA\n"
" * texture2D(texa, tex_a).r\n"
"#ifdef SHD_FILTER_DISPLACE\n"
" * fa\n"
"#endif\n"
" ;\n"
"}\n";
@ -244,6 +273,15 @@ static const char vertex_glsl[] =
"varying vec2 masktex_s[4];\n"
"# endif\n"
"#endif\n"
"/* Gfx Filters: displace */\n"
"#ifdef SHD_FILTER_DISPLACE\n"
"attribute vec2 filter_data_0;\n"
"attribute vec2 filter_data_1;\n"
"attribute vec2 filter_data_2;\n"
"varying vec2 displace_vector;\n"
"varying vec2 displace_min;\n"
"varying vec2 displace_max;\n"
"#endif\n"
"void main()\n"
"{\n"
" gl_Position = mvp * vertex;\n"
@ -307,5 +345,10 @@ static const char vertex_glsl[] =
" pos[3] = vec2(window_Position.y, 1.0 - window_Position.x);\n"
" tex_m = pos[rotation_id] * abs(mask_coord.zw) + mask_coord.xy;\n"
"#endif\n"
"#ifdef SHD_FILTER_DISPLACE\n"
" displace_vector = filter_data_0;\n"
" displace_min = filter_data_1;\n"
" displace_max = filter_data_2;\n"
"#endif\n"
"}\n";

View File

@ -74,10 +74,31 @@ varying vec2 masktex_s[4];
# endif
#endif
#ifdef SHD_FILTER_DISPLACE
uniform sampler2D tex_filter;
varying vec2 displace_vector;
varying vec2 displace_min;
varying vec2 displace_max;
#endif
#ifdef SHD_FILTER_CURVE
uniform sampler2D tex_filter;
#endif
void main()
{
#if defined(SHD_EXTERNAL) || defined(SHD_TEX)
vec2 coord = tex_c;
#endif
vec4 c;
#ifdef SHD_FILTER_DISPLACE
vec2 dxy = (texture2D(tex_filter, tex_c).rg - vec2(0.5, 0.5)) * displace_vector;
float fa = texture2D(tex_filter, tex_c).a;
coord = clamp(tex_c + dxy, displace_min, displace_max);
#endif
#if defined(SHD_YUV) || defined(SHD_NV12) || defined(SHD_YUY2)
float r, g, b, y, u, v, vmu;
# if defined(SHD_YUV)
@ -113,19 +134,19 @@ void main()
c = vec4(r, g, b, 1.0);
#elif defined(SHD_SAM12) || defined(SHD_SAM21)
vec4 col00 = texture2D(tex, tex_c + tex_s[0]).SWZ;
vec4 col01 = texture2D(tex, tex_c + tex_s[1]).SWZ;
vec4 col00 = texture2D(tex, coord + tex_s[0]).SWZ;
vec4 col01 = texture2D(tex, coord + tex_s[1]).SWZ;
c = (col00 + col01) / div_s;
#elif defined(SHD_SAM22)
vec4 col00 = texture2D(tex, tex_c + tex_s[0]).SWZ;
vec4 col01 = texture2D(tex, tex_c + tex_s[1]).SWZ;
vec4 col10 = texture2D(tex, tex_c + tex_s[2]).SWZ;
vec4 col11 = texture2D(tex, tex_c + tex_s[3]).SWZ;
vec4 col00 = texture2D(tex, coord + tex_s[0]).SWZ;
vec4 col01 = texture2D(tex, coord + tex_s[1]).SWZ;
vec4 col10 = texture2D(tex, coord + tex_s[2]).SWZ;
vec4 col11 = texture2D(tex, coord + tex_s[3]).SWZ;
c = (col00 + col01 + col10 + col11) / div_s;
#elif defined(SHD_TEX) || defined(SHD_EXTERNAL)
c = texture2D(tex, tex_c).SWZ;
c = texture2D(tex, coord).SWZ;
#else
c = vec4(1, 1, 1, 1);
@ -171,6 +192,19 @@ void main()
c.a = 1.0;
#endif
#ifdef SHD_TEXA
c *= texture2D(texa, tex_a).r;
#endif
#if defined(SHD_FILTER_CURVE)
float old_alpha = max(c.a, 0.00001);
float new_alpha = texture2D(tex_filter, vec2(old_alpha, 0.0)).a;
c = vec4(texture2D(tex_filter, vec2(c.r / old_alpha, 0.0)).r * new_alpha,
texture2D(tex_filter, vec2(c.g / old_alpha, 0.0)).g * new_alpha,
texture2D(tex_filter, vec2(c.b / old_alpha, 0.0)).b * new_alpha,
new_alpha);
#endif
gl_FragColor =
c
#ifndef SHD_NOMUL
@ -179,8 +213,8 @@ void main()
#ifdef SHD_MASK
* ma
#endif
#ifdef SHD_TEXA
* texture2D(texa, tex_a).r
#ifdef SHD_FILTER_DISPLACE
* fa
#endif
;
}

View File

@ -68,6 +68,16 @@ varying vec2 masktex_s[4];
# endif
#endif
/* Gfx Filters: displace */
#ifdef SHD_FILTER_DISPLACE
attribute vec2 filter_data_0;
attribute vec2 filter_data_1;
attribute vec2 filter_data_2;
varying vec2 displace_vector;
varying vec2 displace_min;
varying vec2 displace_max;
#endif
void main()
{
@ -141,5 +151,11 @@ void main()
pos[3] = vec2(window_Position.y, 1.0 - window_Position.x);
tex_m = pos[rotation_id] * abs(mask_coord.zw) + mask_coord.xy;
#endif
#ifdef SHD_FILTER_DISPLACE
displace_vector = filter_data_0;
displace_min = filter_data_1;
displace_max = filter_data_2;
#endif
}

View File

@ -3031,8 +3031,8 @@ _gfx_filter_func_get(Evas_Filter_Command *cmd)
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_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;
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_FILL: funcptr = gl_filter_fill_func_get(cmd); break;
case EVAS_FILTER_MODE_MASK: funcptr = gl_filter_mask_func_get(cmd); break;
//case EVAS_FILTER_MODE_TRANSFORM: funcptr = gl_filter_transform_func_get(cmd); break;

View File

@ -12,8 +12,8 @@ typedef Eina_Bool (* GL_Filter_Apply_Func) (Render_Engine_GL_Generic *re, Evas_F
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_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);
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_fill_func_get(Evas_Filter_Command *cmd);
GL_Filter_Apply_Func gl_filter_mask_func_get(Evas_Filter_Command *cmd);
//GL_Filter_Apply_Func gl_filter_transform_func_get(Evas_Filter_Command *cmd);

View File

@ -0,0 +1,67 @@
#include "gl_engine_filter.h"
static Eina_Bool
_gl_filter_curve(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
{
Evas_Engine_GL_Context *gc;
Evas_GL_Image *image, *surface;
RGBA_Draw_Context *dc_save;
const uint8_t *points;
int channel;
int w, h;
DEBUG_TIME_BEGIN();
w = cmd->input->w;
h = cmd->input->h;
EINA_SAFETY_ON_FALSE_RETURN_VAL(w == cmd->output->w, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(h == cmd->output->h, EINA_FALSE);
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);
DBG("curve %d @%p -> %d @%p", cmd->input->id, cmd->input->buffer,
cmd->output->id, cmd->output->buffer);
re->window_use(re->software.ob);
gc = re->window_gl_context_get(re->software.ob);
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);
evas_common_draw_context_clip_clip(gc->dc, 0, 0, w, h);
if (cmd->input == cmd->output)
gc->dc->render_op = EVAS_RENDER_COPY;
points = cmd->curve.data;
channel = (int) cmd->curve.channel;
if (cmd->input->alpha_only)
channel = 5;
evas_gl_common_filter_curve_push(gc, image->tex, 0, 0, w, h, points, channel);
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_curve_func_get(Evas_Filter_Command *cmd)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->curve.data, NULL);
return _gl_filter_curve;
}

View File

@ -0,0 +1,85 @@
#include "gl_engine_filter.h"
static Eina_Bool
_gl_filter_displace(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
{
Evas_Engine_GL_Context *gc;
Evas_GL_Image *image, *surface, *orig_map, *use_map;
RGBA_Draw_Context *dc_save;
int x, y, w, h, map_w, map_h;
Eina_Bool nearest = EINA_FALSE;
double dx, dy;
DEBUG_TIME_BEGIN();
w = cmd->input->w;
h = cmd->input->h;
dx = dy = cmd->displacement.intensity;
EINA_SAFETY_ON_FALSE_RETURN_VAL(w == cmd->output->w, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(h == cmd->output->h, EINA_FALSE);
image = evas_ector_buffer_drawable_image_get(cmd->input->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(image, EINA_FALSE);
orig_map = evas_ector_buffer_drawable_image_get(cmd->mask->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(orig_map, EINA_FALSE);
surface = evas_ector_buffer_render_image_get(cmd->output->buffer);
EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
DBG("displace %d @%p map %d %p -> %d @%p", cmd->input->id, cmd->input->buffer,
cmd->mask->id, cmd->mask->buffer, cmd->output->id, cmd->output->buffer);
re->window_use(re->software.ob);
gc = re->window_gl_context_get(re->software.ob);
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);
evas_common_draw_context_clip_clip(gc->dc, 0, 0, w, h);
map_w = (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X) ? w : cmd->mask->w;
map_h = (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y) ? h : cmd->mask->h;
use_map = evas_gl_common_image_virtual_scaled_get(NULL, orig_map, map_w, map_h, EINA_TRUE);
// FIXME: Flags not handled:
// EVAS_FILTER_DISPLACE_BLACK vs. EVAS_FILTER_DISPLACE_STRETCH
if ((cmd->displacement.flags & EVAS_FILTER_DISPLACE_LINEAR) == 0)
nearest = EINA_TRUE;
for (y = 0; y < h; y += map_h)
for (x = 0; x < w; x += map_w)
{
int sw, sh;
sw = MIN(map_w, w - x);
sh = MIN(map_h, h - y);
evas_gl_common_filter_displace_push(gc, image->tex, use_map->tex,
x, y, sw, sh, dx, dy, nearest);
}
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->mask->buffer, orig_map);
evas_ector_buffer_engine_image_release(cmd->output->buffer, surface);
DEBUG_TIME_END();
return EINA_TRUE;
}
GL_Filter_Apply_Func
gl_filter_displace_func_get(Evas_Filter_Command *cmd)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask, NULL);
return _gl_filter_displace;
}