From 0da6278af827f19c7e07ad871e28884bf090ff5a Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 26 Feb 2015 20:42:45 +0900 Subject: [PATCH] Evas masking: Fix masking of maps in GL This completes the transition to auto-scaled mask images when using the GL engine. Now the shaders do the work on-the-fly of resizing the mask. --- .../evas/engines/gl_common/evas_gl_common.h | 2 +- .../evas/engines/gl_common/evas_gl_context.c | 76 ++++++++++--------- .../evas/engines/gl_common/evas_gl_image.c | 48 ++++++------ .../gl_common/shader/evas_gl_shaders.x | 30 +++----- .../gl_common/shader/map_mask_bgra_frag.shd | 1 - .../shader/map_mask_bgra_nomul_vert.shd | 8 +- .../gl_common/shader/map_mask_bgra_vert.shd | 8 +- .../gl_common/shader/map_mask_frag.shd | 1 - .../gl_common/shader/map_mask_nomul_vert.shd | 8 +- .../gl_common/shader/map_mask_vert.shd | 8 +- 10 files changed, 90 insertions(+), 100 deletions(-) diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index b1ba6f360a..7b3be65369 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -754,7 +754,7 @@ void evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *g int npoints, RGBA_Map_Point *p, int clip, int cx, int cy, int cw, int ch, - Evas_GL_Texture *mtex, int mx, int my, int mw, int mh, int mdx, int mdy, int mdw, int mdh, + Evas_GL_Texture *mtex, int mx, int my, int mw, int mh, Eina_Bool mask_smooth, int r, int g, int b, int a, Eina_Bool smooth, Eina_Bool tex_only, 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 2c756db999..cb931ded0d 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -2404,8 +2404,7 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc, int npoints, RGBA_Map_Point *p, int clip, int cx, int cy, int cw, int ch, - Evas_GL_Texture *mtex, int mx, int my, int mw, int mh, - int mdx, int mdy, int mdw, int mdh, + Evas_GL_Texture *mtex, int mx, int my, int mw, int mh, Eina_Bool mask_smooth, int r, int g, int b, int a, Eina_Bool smooth, Eina_Bool tex_only, Evas_Colorspace cspace) @@ -2606,7 +2605,7 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc, gc->pipe[pn].array.use_texm = !!mtex; gc->pipe[pn].array.use_texa = !!mtex; gc->pipe[pn].array.use_texsam = gc->pipe[pn].array.use_texm; - gc->pipe[pn].array.mask_smooth = EINA_FALSE; + gc->pipe[pn].array.mask_smooth = mask_smooth; pipe_region_expand(gc, pn, x, y, w, h); PIPE_GROW(gc, pn, 6); @@ -2668,12 +2667,8 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc, if (mtex) { - GLfloat glmdx = 0.f, glmdy = 0.f, glmdw = 1.f, glmdh = 1.f, yinv = -1.f; - GLfloat gw = gc->w, gh = gc->h; - - // Note: I couldn't write any test case where it was necessary - // to know the mask position in its texture. Thus these unused vars. - (void) mx; (void) my; (void) mw; (void) mh; + double glmx, glmy, glmw, glmh, yinv = -1.f; + double gw = gc->w, gh = gc->h; if (!((gc->pipe[0].shader.surface == gc->def_surface) || (!gc->pipe[0].shader.surface))) @@ -2682,40 +2677,47 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc, gh = gc->pipe[0].shader.surface->h; yinv = 1.f; } + if (!gw || !gh || !mw || !mh || !mtex->pt->w || !mtex->pt->h) + goto mask_error; - if (gw) glmdx = (GLfloat) mdx / (GLfloat) gw; - if (gh) glmdy = (GLfloat) mdy / (GLfloat) gh; - if (mdw) glmdw = (GLfloat) gw / (GLfloat) mdw; - if (mdh) glmdh = (GLfloat) gh / (GLfloat) mdh; + // vertex shader: tex_m = (X,Y) * tex_coordm + tex_sample + // tex_coordm + glmx = (double)((mtex->x * mw) - (mtex->w * mx)) / (double)(mw * mtex->pt->w); + glmy = (double)((mtex->y * mh) - (mtex->h * my)) / (double)(mh * mtex->pt->h); + PUSH_TEXM(pn, glmx, glmy); + PUSH_TEXM(pn, glmx, glmy); + PUSH_TEXM(pn, glmx, glmy); + PUSH_TEXM(pn, glmx, glmy); + PUSH_TEXM(pn, glmx, glmy); + PUSH_TEXM(pn, glmx, glmy); - // tex_coordm: mask x,y (on canvas) - PUSH_TEXM(pn, glmdx, glmdy); - PUSH_TEXM(pn, glmdx, glmdy); - PUSH_TEXM(pn, glmdx, glmdy); - PUSH_TEXM(pn, glmdx, glmdy); - PUSH_TEXM(pn, glmdx, glmdy); - PUSH_TEXM(pn, glmdx, glmdy); + // tex_sample + glmw = (double)(gw * mtex->w) / (double)(mw * mtex->pt->w); + glmh = (double)(gh * mtex->h) / (double)(mh * mtex->pt->h); + PUSH_TEXSAM(pn, glmw, glmh); + PUSH_TEXSAM(pn, glmw, glmh); + PUSH_TEXSAM(pn, glmw, glmh); + PUSH_TEXSAM(pn, glmw, glmh); + PUSH_TEXSAM(pn, glmw, glmh); + PUSH_TEXSAM(pn, glmw, glmh); - // tex_sample: mask 1/w, 1/h - PUSH_TEXSAM(pn, glmdw, glmdh); - PUSH_TEXSAM(pn, glmdw, glmdh); - PUSH_TEXSAM(pn, glmdw, glmdh); - PUSH_TEXSAM(pn, glmdw, glmdh); - PUSH_TEXSAM(pn, glmdw, glmdh); - PUSH_TEXSAM(pn, glmdw, glmdh); + // tex_coorda: Y-invert flag + PUSH_TEXA(pn, 1.0, yinv); + PUSH_TEXA(pn, 1.0, yinv); + PUSH_TEXA(pn, 1.0, yinv); + PUSH_TEXA(pn, 1.0, yinv); + PUSH_TEXA(pn, 1.0, yinv); + PUSH_TEXA(pn, 1.0, yinv); - // tex_coorda: mask Y-invert flag - PUSH_TEXA(pn, 1.f, yinv); - PUSH_TEXA(pn, 1.f, yinv); - PUSH_TEXA(pn, 1.f, yinv); - PUSH_TEXA(pn, 1.f, yinv); - PUSH_TEXA(pn, 1.f, yinv); - PUSH_TEXA(pn, 1.f, yinv); - - //DBG("Orig %d,%d - %dx%d --> %f,%f - %f x %f", mdx, mdy, mdw, mdh, - // glmdx, glmdy, glmdw, glmdh); + /* + DBG("Map mask: %d,%d %dx%d --> %f , %f - %f x %f @ %f %f [gc %dx%d, tex %d,%d %dx%d, pt %dx%d]", + mx, my, mw, mh, + glmx, glmy, glmw, glmh, 1.0, yinv, + gc->w, gc->h, mtex->x, mtex->y, mtex->w, mtex->h, mtex->pt->w, mtex->pt->h); + */ } +mask_error: if (!flat) { shader_array_flush(gc); diff --git a/src/modules/evas/engines/gl_common/evas_gl_image.c b/src/modules/evas/engines/gl_common/evas_gl_image.c index 2fdc60889f..c897bd261c 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_image.c +++ b/src/modules/evas/engines/gl_common/evas_gl_image.c @@ -923,9 +923,11 @@ void evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, int npoints, RGBA_Map_Point *p, int smooth, int level EINA_UNUSED) { - int mmx = 0, mmy = 0, mmw = 0, mmh = 0, mdx = 0, mdy = 0, mdw = 0, mdh = 0; - Evas_GL_Texture *mtex = NULL; - RGBA_Draw_Context *dc; + int mx = 0, my = 0, mw = 0, mh = 0; + RGBA_Draw_Context *dc = gc->dc; + Eina_Bool mask_smooth = EINA_FALSE; + Evas_GL_Image *mask = dc->clip.mask; + Evas_GL_Texture *mtex = mask ? mask->tex : NULL; int r, g, b, a; int c, cx, cy, cw, ch; @@ -951,30 +953,32 @@ evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im, if (!im->tex) return; im->tex->im = im; - if (dc->clip.mask) + if (mtex && mtex->pt && mtex->pt->w && mtex->pt->h) { - Evas_GL_Image *mask = dc->clip.mask; - double mx, my, mw, mh; - - mdx = mx = dc->clip.mask_x; - mdy = my = dc->clip.mask_y; - mdw = mw = mask->w; - mdh = mh = mask->h; - if (c) RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch); - //RECTS_CLIP_TO_RECT(mx, my, mw, mh, dx, dy, dw, dh); - mmx = mx - dc->clip.mask_x; - mmy = my - dc->clip.mask_y; - mmw = mw; - mmh = mh; - mtex = mask->tex; - // TODO: implement support for scaled masks - //if (mask->scaled.origin) - //mask_smooth = mask->scaled.smooth; + // canvas coords + mx = dc->clip.mask_x; + my = dc->clip.mask_y; + if (mask->scaled.origin) + { + mw = mask->scaled.w; + mh = mask->scaled.h; + //scalex = mask->w / (double)mask->scaled.w; + //scaley = mask->h / (double)mask->scaled.h; + mask_smooth = mask->scaled.smooth; + } + else + { + mw = mask->w; + mh = mask->h; + } + //if (c) RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch); + //mx = mx - dc->clip.mask_x; + //my = my - dc->clip.mask_y; } evas_gl_common_context_image_map_push(gc, im->tex, npoints, p, c, cx, cy, cw, ch, - mtex, mmx, mmy, mmw, mmh, mdx, mdy, mdw, mdh, + mtex, mx, my, mw, mh, mask_smooth, r, g, b, a, smooth, im->tex_only, im->cs.space); } diff --git a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x index 4789e40424..5abc028a17 100644 --- a/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x +++ b/src/modules/evas/engines/gl_common/shader/evas_gl_shaders.x @@ -2715,7 +2715,6 @@ static const char const map_mask_frag_glsl[] = "varying vec4 col;\n" "void main()\n" "{\n" - " // FIXME: Use mask coordinates within its texture\n" " // FIXME: Fix Mach band effect using proper 4-point color interpolation\n" " gl_FragColor = texture2D(tex, tex_c).bgra * texture2D(texm, tex_m).a * col;\n" "}\n"; @@ -2741,10 +2740,9 @@ static const char const map_mask_vert_glsl[] = " tex_c = tex_coord;\n" " col = color;\n" " // tex_coorda contains the Y-invert flag\n" - " // tex_coordm contains the X,Y position of the mask\n" - " // tex_sample contains the W,H size of the mask (inverted)\n" - " vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" - " tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample;\n" + " // position on screen in [0..1] range of current pixel\n" + " vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" + " tex_m = mask_Position.xy * tex_sample + tex_coordm;\n" "}\n"; Evas_GL_Program_Source shader_map_mask_vert_src = { @@ -2787,10 +2785,9 @@ static const char const map_mask_nomul_vert_glsl[] = " gl_Position = mvp * vertex;\n" " tex_c = tex_coord;\n" " // tex_coorda contains the Y-invert flag\n" - " // tex_coordm contains the X,Y position of the mask\n" - " // tex_sample contains the W,H size of the mask (inverted)\n" - " vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" - " tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample;\n" + " // position on screen in [0..1] range of current pixel\n" + " vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" + " tex_m = mask_Position.xy * tex_sample + tex_coordm;\n" "}\n"; Evas_GL_Program_Source shader_map_mask_nomul_vert_src = { @@ -2812,7 +2809,6 @@ static const char const map_mask_bgra_frag_glsl[] = "varying vec4 col;\n" "void main()\n" "{\n" - " // FIXME: Use mask coordinates within its texture\n" " // FIXME: Fix Mach band effect using proper 4-point color interpolation\n" " gl_FragColor = texture2D(tex, tex_c) * texture2D(texm, tex_m).a * col;\n" "}\n"; @@ -2838,10 +2834,9 @@ static const char const map_mask_bgra_vert_glsl[] = " tex_c = tex_coord;\n" " col = color;\n" " // tex_coorda contains the Y-invert flag\n" - " // tex_coordm contains the X,Y position of the mask\n" - " // tex_sample contains the W,H size of the mask (inverted)\n" - " vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" - " tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample;\n" + " // position on screen in [0..1] range of current pixel\n" + " vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" + " tex_m = mask_Position.xy * tex_sample + tex_coordm;\n" "}\n"; Evas_GL_Program_Source shader_map_mask_bgra_vert_src = { @@ -2884,10 +2879,9 @@ static const char const map_mask_bgra_nomul_vert_glsl[] = " gl_Position = mvp * vertex;\n" " tex_c = tex_coord;\n" " // tex_coorda contains the Y-invert flag\n" - " // tex_coordm contains the X,Y position of the mask\n" - " // tex_sample contains the W,H size of the mask (inverted)\n" - " vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" - " tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample;\n" + " // position on screen in [0..1] range of current pixel\n" + " vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);\n" + " tex_m = mask_Position.xy * tex_sample + tex_coordm;\n" "}\n"; Evas_GL_Program_Source shader_map_mask_bgra_nomul_vert_src = { diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_frag.shd b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_frag.shd index ed4fdf0f1c..be952b7f02 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_frag.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_frag.shd @@ -10,7 +10,6 @@ varying vec2 tex_c, tex_m; varying vec4 col; void main() { - // FIXME: Use mask coordinates within its texture // FIXME: Fix Mach band effect using proper 4-point color interpolation gl_FragColor = texture2D(tex, tex_c) * texture2D(texm, tex_m).a * col; } diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_nomul_vert.shd b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_nomul_vert.shd index 7e2b02e5e5..49da5bcc97 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_nomul_vert.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_nomul_vert.shd @@ -11,9 +11,7 @@ void main() tex_c = tex_coord; // tex_coorda contains the Y-invert flag - // tex_coordm contains the X,Y position of the mask - // tex_sample contains the W,H size of the mask (inverted) - - vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); - tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample; + // position on screen in [0..1] range of current pixel + vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); + tex_m = mask_Position.xy * tex_sample + tex_coordm; } diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_vert.shd b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_vert.shd index c1c132b929..2d2afa9b03 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_bgra_vert.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_bgra_vert.shd @@ -13,9 +13,7 @@ void main() col = color; // tex_coorda contains the Y-invert flag - // tex_coordm contains the X,Y position of the mask - // tex_sample contains the W,H size of the mask (inverted) - - vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); - tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample; + // position on screen in [0..1] range of current pixel + vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); + tex_m = mask_Position.xy * tex_sample + tex_coordm; } diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_frag.shd b/src/modules/evas/engines/gl_common/shader/map_mask_frag.shd index 7a7579a357..17e91f4657 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_frag.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_frag.shd @@ -10,7 +10,6 @@ varying vec2 tex_c, tex_m; varying vec4 col; void main() { - // FIXME: Use mask coordinates within its texture // FIXME: Fix Mach band effect using proper 4-point color interpolation gl_FragColor = texture2D(tex, tex_c).bgra * texture2D(texm, tex_m).a * col; } diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_nomul_vert.shd b/src/modules/evas/engines/gl_common/shader/map_mask_nomul_vert.shd index 7e2b02e5e5..49da5bcc97 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_nomul_vert.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_nomul_vert.shd @@ -11,9 +11,7 @@ void main() tex_c = tex_coord; // tex_coorda contains the Y-invert flag - // tex_coordm contains the X,Y position of the mask - // tex_sample contains the W,H size of the mask (inverted) - - vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); - tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample; + // position on screen in [0..1] range of current pixel + vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); + tex_m = mask_Position.xy * tex_sample + tex_coordm; } diff --git a/src/modules/evas/engines/gl_common/shader/map_mask_vert.shd b/src/modules/evas/engines/gl_common/shader/map_mask_vert.shd index c1c132b929..2d2afa9b03 100644 --- a/src/modules/evas/engines/gl_common/shader/map_mask_vert.shd +++ b/src/modules/evas/engines/gl_common/shader/map_mask_vert.shd @@ -13,9 +13,7 @@ void main() col = color; // tex_coorda contains the Y-invert flag - // tex_coordm contains the X,Y position of the mask - // tex_sample contains the W,H size of the mask (inverted) - - vec4 mask_Position = mvp * vertex * vec4(tex_coorda.x * 0.5, tex_coorda.y * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); - tex_m = vec2(mask_Position.xy - tex_coordm) * tex_sample; + // position on screen in [0..1] range of current pixel + vec4 mask_Position = mvp * vertex * vec4(0.5, sign(tex_coorda.y) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0); + tex_m = mask_Position.xy * tex_sample + tex_coordm; }