jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=45548e8358b0affcaa9738ad1b5ae5b542c9349b
commit 45548e8358b0affcaa9738ad1b5ae5b542c9349b Author: Jean-Philippe Andre <jp.an...@samsung.com> Date: Fri Mar 31 13:10:41 2017 +0900 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. --- .../evas/engines/gl_common/evas_gl_context.c | 100 +++++++++-------- .../engines/gl_generic/filters/gl_filter_blur.c | 120 +++++++++++++++++---- 2 files changed, 159 insertions(+), 61 deletions(-) diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index d19eb69..b61cc6a 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -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,39 +3467,13 @@ 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); - pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog, - sx, sy, dw, dh, blend, smooth, - 0, 0, 0, 0, 0, EINA_FALSE); - - gc->pipe[pn].region.type = type; - gc->pipe[pn].shader.prog = prog; - gc->pipe[pn].shader.cur_tex = tex->pt->texture; - gc->pipe[pn].shader.cur_texm = 0; - gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D; - gc->pipe[pn].shader.smooth = smooth; - gc->pipe[pn].shader.mask_smooth = 0; - gc->pipe[pn].shader.blend = blend; - gc->pipe[pn].shader.render_op = gc->dc->render_op; - gc->pipe[pn].shader.clip = 0; - gc->pipe[pn].shader.cx = 0; - gc->pipe[pn].shader.cy = 0; - gc->pipe[pn].shader.cw = 0; - gc->pipe[pn].shader.ch = 0; - gc->pipe[pn].array.line = 0; - gc->pipe[pn].array.use_vertex = 1; - gc->pipe[pn].array.use_color = !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, dx, dy, dw, dh); - PIPE_GROW(gc, pn, 6); + pw = tex->pt->w; + ph = tex->pt->h; + texlen = horiz ? pw : ph; /* Convert double data to RGBA pixel data. * @@ -3525,7 +3503,7 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, } // Prepare attributes & uniforms - _filter_data_prepare(gc, pn, prog, 0); + _filter_data_prepare(gc, prog, 0); if (!prog->filter->uniform.known_locations) { prog->filter->uniform.known_locations = EINA_TRUE; @@ -3534,6 +3512,47 @@ evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc, 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); + + gc->pipe[pn].region.type = type; + gc->pipe[pn].shader.prog = prog; + gc->pipe[pn].shader.cur_tex = tex->pt->texture; + gc->pipe[pn].shader.cur_texm = 0; + gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D; + gc->pipe[pn].shader.smooth = smooth; + gc->pipe[pn].shader.mask_smooth = 0; + gc->pipe[pn].shader.blend = blend; + gc->pipe[pn].shader.render_op = gc->dc->render_op; + gc->pipe[pn].shader.clip = 0; + gc->pipe[pn].shader.cx = 0; + gc->pipe[pn].shader.cy = 0; + gc->pipe[pn].shader.cw = 0; + gc->pipe[pn].shader.ch = 0; + gc->pipe[pn].array.line = 0; + gc->pipe[pn].array.use_vertex = 1; + gc->pipe[pn].array.use_color = !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, dx, dy, dw, dh); + PIPE_GROW(gc, pn, 6); + + _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; diff --git a/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c b/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c index a1fc0ed..8c78f8c 100644 --- a/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c +++ b/src/modules/evas/engines/gl_generic/filters/gl_filter_blur.c @@ -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); --