forked from enlightenment/efl
evas filters: Implement obscure support for gl blur
This can help with performance when a large region of the filtered image (eg. snapshot) is fully hidden by an opaque object. For instance the window border is hidden by the opaque window content.
This commit is contained in:
parent
08a8072571
commit
45548e8358
|
@ -3139,13 +3139,17 @@ _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)
|
||||
_filter_data_alloc(Evas_Engine_GL_Context *gc, int pn, int count)
|
||||
{
|
||||
gc->pipe[pn].array.filter_data_count = count;
|
||||
if (count) gc->pipe[pn].array.filter_data = malloc(count * 2 * sizeof(GLfloat));
|
||||
else gc->pipe[pn].array.filter_data = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_filter_data_prepare(Evas_Engine_GL_Context *gc EINA_UNUSED,
|
||||
Evas_GL_Program *prog, int count)
|
||||
{
|
||||
if (!prog->filter) prog->filter = calloc(1, sizeof(*prog->filter));
|
||||
if (!prog->filter->attribute.known_locations)
|
||||
{
|
||||
|
@ -3224,7 +3228,8 @@ evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc,
|
|||
// displace properties
|
||||
gc->pipe[pn].shader.filter.map_tex = map_tex->pt->texture;
|
||||
gc->pipe[pn].shader.filter.map_nearest = nearest;
|
||||
_filter_data_prepare(gc, pn, prog, 3);
|
||||
_filter_data_prepare(gc, prog, 3);
|
||||
_filter_data_alloc(gc, pn, 3);
|
||||
|
||||
sx = x;
|
||||
sy = y;
|
||||
|
@ -3439,7 +3444,7 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
const double * const offsets, int count,
|
||||
double radius, Eina_Bool horiz)
|
||||
{
|
||||
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph;
|
||||
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph, texlen;
|
||||
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
||||
GLfloat offsetx, offsety;
|
||||
int r, g, b, a, nomul = 0, pn;
|
||||
|
@ -3447,11 +3452,10 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
Eina_Bool blend = EINA_TRUE;
|
||||
Eina_Bool smooth = EINA_TRUE;
|
||||
Shader_Type type = horiz ? SHD_FILTER_BLUR_X : SHD_FILTER_BLUR_Y;
|
||||
Eina_Bool update_uniforms = EINA_FALSE;
|
||||
GLuint *map_tex_data;
|
||||
double sum;
|
||||
|
||||
//shader_array_flush(gc);
|
||||
|
||||
r = R_VAL(&gc->dc->mul.col);
|
||||
g = G_VAL(&gc->dc->mul.col);
|
||||
b = B_VAL(&gc->dc->mul.col);
|
||||
|
@ -3463,9 +3467,59 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
sw, sh, dw, dh, 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);
|
||||
|
||||
pw = tex->pt->w;
|
||||
ph = tex->pt->h;
|
||||
texlen = horiz ? pw : ph;
|
||||
|
||||
/* Convert double data to RGBA pixel data.
|
||||
*
|
||||
* We are not using GL_FLOAT or GL_DOUBLE because:
|
||||
* - It's not as portable (needs extensions),
|
||||
* - GL_DOUBLE didn't work during my tests (dunno why),
|
||||
* - GL_FLOAT didn't seem to carry the proper precision all the way to
|
||||
* the fragment shader,
|
||||
* - Real data buffers are not available in GLES 2.0,
|
||||
* - GL_RGBA is 100% portable.
|
||||
*/
|
||||
map_tex_data = alloca(2 * count * sizeof(*map_tex_data));
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
GLuint val;
|
||||
|
||||
if (k == 0) sum = weights[k];
|
||||
else sum += 2.0 * weights[k];
|
||||
|
||||
// Weight is always > 0.0 and < 255.0 by maths
|
||||
val = (GLuint) (weights[k] * 256.0 * 256.0 * 256.0);
|
||||
map_tex_data[k] = val;
|
||||
|
||||
// Offset is always in [0.0 , 1.0] by definition
|
||||
val = (GLuint) (offsets[k] * 256.0 * 256.0 * 256.0);
|
||||
map_tex_data[k + count] = val;
|
||||
}
|
||||
|
||||
// Prepare attributes & uniforms
|
||||
_filter_data_prepare(gc, prog, 0);
|
||||
if (!prog->filter->uniform.known_locations)
|
||||
{
|
||||
prog->filter->uniform.known_locations = EINA_TRUE;
|
||||
prog->filter->uniform.blur_count_loc = glGetUniformLocation(prog->prog, "blur_count");
|
||||
prog->filter->uniform.blur_texlen_loc = glGetUniformLocation(prog->prog, "blur_texlen");
|
||||
prog->filter->uniform.blur_div_loc = glGetUniformLocation(prog->prog, "blur_div");
|
||||
}
|
||||
|
||||
if ((prog->filter->uniform.blur_count_value != count - 1) ||
|
||||
(!EINA_FLT_EQ(prog->filter->uniform.blur_texlen_value, texlen)) ||
|
||||
(!EINA_FLT_EQ(prog->filter->uniform.blur_div_value, sum)))
|
||||
{
|
||||
update_uniforms = EINA_TRUE;
|
||||
shader_array_flush(gc);
|
||||
}
|
||||
|
||||
pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog,
|
||||
sx, sy, dw, dh, blend, smooth,
|
||||
0, 0, 0, 0, 0, EINA_FALSE);
|
||||
|
@ -3497,42 +3551,7 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
pipe_region_expand(gc, pn, dx, dy, dw, dh);
|
||||
PIPE_GROW(gc, pn, 6);
|
||||
|
||||
/* Convert double data to RGBA pixel data.
|
||||
*
|
||||
* We are not using GL_FLOAT or GL_DOUBLE because:
|
||||
* - It's not as portable (needs extensions),
|
||||
* - GL_DOUBLE didn't work during my tests (dunno why),
|
||||
* - GL_FLOAT didn't seem to carry the proper precision all the way to
|
||||
* the fragment shader,
|
||||
* - Real data buffers are not available in GLES 2.0,
|
||||
* - GL_RGBA is 100% portable.
|
||||
*/
|
||||
map_tex_data = alloca(2 * count * sizeof(*map_tex_data));
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
GLuint val;
|
||||
|
||||
if (k == 0) sum = weights[k];
|
||||
else sum += 2.0 * weights[k];
|
||||
|
||||
// Weight is always > 0.0 and < 255.0 by maths
|
||||
val = (GLuint) (weights[k] * 256.0 * 256.0 * 256.0);
|
||||
map_tex_data[k] = val;
|
||||
|
||||
// Offset is always in [0.0 , 1.0] by definition
|
||||
val = (GLuint) (offsets[k] * 256.0 * 256.0 * 256.0);
|
||||
map_tex_data[k + count] = val;
|
||||
}
|
||||
|
||||
// Prepare attributes & uniforms
|
||||
_filter_data_prepare(gc, pn, prog, 0);
|
||||
if (!prog->filter->uniform.known_locations)
|
||||
{
|
||||
prog->filter->uniform.known_locations = EINA_TRUE;
|
||||
prog->filter->uniform.blur_count_loc = glGetUniformLocation(prog->prog, "blur_count");
|
||||
prog->filter->uniform.blur_texlen_loc = glGetUniformLocation(prog->prog, "blur_texlen");
|
||||
prog->filter->uniform.blur_div_loc = glGetUniformLocation(prog->prog, "blur_div");
|
||||
}
|
||||
_filter_data_alloc(gc, pn, 0);
|
||||
|
||||
// Synchronous upload of Nx2 RGBA texture
|
||||
if (!EINA_DBL_EQ(prog->filter->blur_radius, radius))
|
||||
|
@ -3553,10 +3572,10 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, count, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, map_tex_data);
|
||||
}
|
||||
|
||||
//if (update_uniforms)
|
||||
if (update_uniforms)
|
||||
{
|
||||
prog->filter->uniform.blur_count_value = count - 1;
|
||||
prog->filter->uniform.blur_texlen_value = horiz ? sw : sh;
|
||||
prog->filter->uniform.blur_texlen_value = texlen;
|
||||
prog->filter->uniform.blur_div_value = sum;
|
||||
glUseProgram(prog->prog);
|
||||
glUniform1i(prog->filter->uniform.blur_count_loc, prog->filter->uniform.blur_count_value);
|
||||
|
@ -3569,9 +3588,6 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|||
gc->pipe[pn].shader.filter.map_nearest = EINA_TRUE;
|
||||
gc->pipe[pn].shader.filter.map_delete = EINA_FALSE;
|
||||
|
||||
pw = tex->pt->w;
|
||||
ph = tex->pt->h;
|
||||
|
||||
ox1 = sx;
|
||||
oy1 = sy;
|
||||
ox2 = sx + sw;
|
||||
|
|
|
@ -81,6 +81,36 @@ _gaussian_interpolate(double **weights, double **offsets, double radius)
|
|||
return count;
|
||||
}
|
||||
|
||||
static inline Eina_Rectangle
|
||||
_rect(int x, int y, int w, int h, int maxw, int maxh)
|
||||
{
|
||||
Eina_Rectangle rect;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
w -= (-x);
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
h -= (-y);
|
||||
y = 0;
|
||||
}
|
||||
if ((x + w) > maxw) w = maxw - x;
|
||||
if ((y + h) > maxh) h = maxh - y;
|
||||
if (w < 0) w = 0;
|
||||
if (h < 0) h = 0;
|
||||
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = w;
|
||||
rect.h = h;
|
||||
return rect;
|
||||
}
|
||||
|
||||
#define S_RECT(_x, _y, _w, _h) _rect(_x, _y, _w, _h, s_w, s_h)
|
||||
#define D_RECT(_x, _y, _w, _h) _rect(_x, _y, _w, _h, d_w, d_h)
|
||||
|
||||
static Eina_Bool
|
||||
_gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
|
||||
{
|
||||
|
@ -89,11 +119,19 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
|
|||
RGBA_Draw_Context *dc_save;
|
||||
Eina_Bool horiz;
|
||||
double sx, sy, sw, sh, ssx, ssy, ssw, ssh, dx, dy, dw, dh, radius;
|
||||
int nx, ny, nw, nh, count = 0;
|
||||
double s_w, s_h, d_w, d_h;
|
||||
Eina_Rectangle s_ob, d_ob, s_region[4], d_region[4];
|
||||
int nx, ny, nw, nh, regions, count = 0;
|
||||
double *weights, *offsets;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -121,22 +159,6 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
|
|||
cmd->output->id, cmd->output->buffer,
|
||||
radius, horiz ? "X" : "Y");
|
||||
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
sw = cmd->input->w;
|
||||
sh = cmd->input->h;
|
||||
dx = cmd->draw.ox;
|
||||
dy = cmd->draw.oy;
|
||||
dw = cmd->output->w;
|
||||
dh = cmd->output->h;
|
||||
|
||||
nx = dx; ny = dy; nw = dw; nh = dh;
|
||||
RECTS_CLIP_TO_RECT(nx, ny, nw, nh, 0, 0, cmd->output->w, cmd->output->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);
|
||||
|
||||
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);
|
||||
|
@ -148,8 +170,68 @@ _gl_filter_blur(Render_Engine_GL_Generic *re, Evas_Filter_Command *cmd)
|
|||
gc->dc->render_op = _gfx_to_evas_render_op(cmd->draw.rop);
|
||||
|
||||
count = _gaussian_interpolate(&weights, &offsets, radius);
|
||||
evas_gl_common_filter_blur_push(gc, image->tex, ssx, ssy, ssw, ssh, dx, dy, dw, dh,
|
||||
weights, offsets, count, radius, horiz);
|
||||
|
||||
d_ob = cmd->ctx->obscured.effective;
|
||||
s_ob.x = d_ob.x * s_w / d_w;
|
||||
s_ob.y = d_ob.y * s_h / d_h;
|
||||
s_ob.w = d_ob.w * s_w / d_w;
|
||||
s_ob.h = d_ob.h * s_h / d_h;
|
||||
if (!d_ob.w || !d_ob.h)
|
||||
{
|
||||
s_region[0] = S_RECT(0, 0, s_w, s_h);
|
||||
d_region[0] = D_RECT(0, 0, d_w, d_h);
|
||||
regions = 1;
|
||||
}
|
||||
else if (horiz)
|
||||
{
|
||||
// top (full), left, right, bottom (full)
|
||||
s_region[0] = S_RECT(0, 0, s_w, s_ob.y);
|
||||
d_region[0] = D_RECT(0, 0, d_w, d_ob.y);
|
||||
s_region[1] = S_RECT(0, s_ob.y, s_ob.x, s_ob.h);
|
||||
d_region[1] = D_RECT(0, d_ob.y, d_ob.x, d_ob.h);
|
||||
s_region[2] = S_RECT(s_ob.x + s_ob.w, s_ob.y, s_w - s_ob.x - s_ob.w, s_ob.h);
|
||||
d_region[2] = D_RECT(d_ob.x + d_ob.w, d_ob.y, d_w - d_ob.x - d_ob.w, d_ob.h);
|
||||
s_region[3] = S_RECT(0, s_ob.y + s_ob.h, s_w, s_h - s_ob.y - s_ob.h);
|
||||
d_region[3] = D_RECT(0, d_ob.y + d_ob.h, d_w, d_h - d_ob.y - d_ob.h);
|
||||
regions = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// left (full), top, bottom, right (full)
|
||||
s_region[0] = S_RECT(0, 0, s_ob.x, s_h);
|
||||
d_region[0] = D_RECT(0, 0, d_ob.x, d_h);
|
||||
s_region[1] = S_RECT(s_ob.x, 0, s_ob.w, s_ob.y);
|
||||
d_region[1] = D_RECT(d_ob.x, 0, d_ob.w, d_ob.y);
|
||||
s_region[2] = S_RECT(s_ob.x, s_ob.y + s_ob.h, s_ob.w, s_h - s_ob.y - s_ob.h);
|
||||
d_region[2] = D_RECT(d_ob.x, d_ob.y + d_ob.h, d_ob.w, d_h - d_ob.y - d_ob.h);
|
||||
s_region[3] = S_RECT(s_ob.x + s_ob.w, 0, s_w - s_ob.x - s_ob.w, s_h);
|
||||
d_region[3] = D_RECT(d_ob.x + d_ob.w, 0, d_w - d_ob.x - d_ob.w, d_h);
|
||||
regions = 4;
|
||||
}
|
||||
|
||||
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_blur_push(gc, image->tex, ssx, ssy, ssw, ssh, dx, dy, dw, dh,
|
||||
weights, offsets, count, radius, horiz);
|
||||
}
|
||||
|
||||
free(weights);
|
||||
free(offsets);
|
||||
|
||||
|
|
Loading…
Reference in New Issue