From 685288216f8c23751a6b156921a5d6daf43d46eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Sun, 19 Jan 2020 20:08:23 +0100 Subject: [PATCH] gl renderer: Move rect transformation to the vertex shader No need to do this for every fragment. --- gsk/gl/gskglrenderer.c | 1 + gsk/gl/gskglshaderbuilder.c | 12 ++- gsk/gl/gskglshaderbuilderprivate.h | 2 + gsk/meson.build | 1 + gsk/resources/glsl/border.glsl | 38 +++++---- gsk/resources/glsl/inset_shadow.glsl | 38 +++++---- gsk/resources/glsl/outset_shadow.glsl | 14 ++-- gsk/resources/glsl/preamble.fs.glsl | 80 ++----------------- gsk/resources/glsl/preamble.glsl | 37 +++++++++ gsk/resources/glsl/preamble.vs.glsl | 66 ++++++++++++--- .../glsl/unblurred_outset_shadow.glsl | 40 ++++++---- 11 files changed, 190 insertions(+), 139 deletions(-) create mode 100644 gsk/resources/glsl/preamble.glsl diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 1dd08f88e7..2200ef54bd 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -2565,6 +2565,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, gboolean success = TRUE; gsk_gl_shader_builder_init (&shader_builder, + "/org/gtk/libgsk/glsl/preamble.glsl", "/org/gtk/libgsk/glsl/preamble.vs.glsl", "/org/gtk/libgsk/glsl/preamble.fs.glsl"); diff --git a/gsk/gl/gskglshaderbuilder.c b/gsk/gl/gskglshaderbuilder.c index f28bf127f7..a133527784 100644 --- a/gsk/gl/gskglshaderbuilder.c +++ b/gsk/gl/gskglshaderbuilder.c @@ -9,14 +9,17 @@ void gsk_gl_shader_builder_init (GskGLShaderBuilder *self, + const char *common_preamble_resource_path, const char *vs_preamble_resource_path, const char *fs_preamble_resource_path) { memset (self, 0, sizeof (*self)); + self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL); self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL); self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL); + g_assert (self->preamble); g_assert (self->vs_preamble); g_assert (self->fs_preamble); } @@ -24,6 +27,7 @@ gsk_gl_shader_builder_init (GskGLShaderBuilder *self, void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self) { + g_bytes_unref (self->preamble); g_bytes_unref (self->vs_preamble); g_bytes_unref (self->fs_preamble); } @@ -102,13 +106,14 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, "#version %d\n", self->version); vertex_id = glCreateShader (GL_VERTEX_SHADER); - glShaderSource (vertex_id, 7, + glShaderSource (vertex_id, 8, (const char *[]) { version_buffer, self->debugging ? "#define GSK_DEBUG 1\n" : "", self->legacy ? "#define GSK_LEGACY 1\n" : "", self->gl3 ? "#define GSK_GL3 1\n" : "", self->gles ? "#define GSK_GLES 1\n" : "", + g_bytes_get_data (self->preamble, NULL), g_bytes_get_data (self->vs_preamble, NULL), vertex_shader_start }, @@ -119,6 +124,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, -1, -1, -1, + -1, fragment_shader_start - vertex_shader_start }); glCompileShader (vertex_id); @@ -130,13 +136,14 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, } fragment_id = glCreateShader (GL_FRAGMENT_SHADER); - glShaderSource (fragment_id, 7, + glShaderSource (fragment_id, 8, (const char *[]) { version_buffer, self->debugging ? "#define GSK_DEBUG 1\n" : "", self->legacy ? "#define GSK_LEGACY 1\n" : "", self->gl3 ? "#define GSK_GL3 1\n" : "", self->gles ? "#define GSK_GLES 1\n" : "", + g_bytes_get_data (self->preamble, NULL), g_bytes_get_data (self->fs_preamble, NULL), fragment_shader_start }, @@ -148,6 +155,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, -1, -1, -1, + -1, }); glCompileShader (fragment_id); diff --git a/gsk/gl/gskglshaderbuilderprivate.h b/gsk/gl/gskglshaderbuilderprivate.h index 209fa5ff91..ec9cd66845 100644 --- a/gsk/gl/gskglshaderbuilderprivate.h +++ b/gsk/gl/gskglshaderbuilderprivate.h @@ -8,6 +8,7 @@ G_BEGIN_DECLS typedef struct { + GBytes *preamble; GBytes *vs_preamble; GBytes *fs_preamble; @@ -22,6 +23,7 @@ typedef struct void gsk_gl_shader_builder_init (GskGLShaderBuilder *self, + const char *common_preamble_resource_path, const char *vs_preamble_resource_path, const char *fs_preamble_resource_path); void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self); diff --git a/gsk/meson.build b/gsk/meson.build index 6dd4925155..8aeae9e7e8 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -1,4 +1,5 @@ gsk_private_gl_shaders = [ + 'resources/glsl/preamble.glsl', 'resources/glsl/preamble.fs.glsl', 'resources/glsl/preamble.vs.glsl', 'resources/glsl/border.glsl', diff --git a/gsk/resources/glsl/border.glsl b/gsk/resources/glsl/border.glsl index 505c850217..812d365431 100644 --- a/gsk/resources/glsl/border.glsl +++ b/gsk/resources/glsl/border.glsl @@ -1,7 +1,11 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,18 +13,6 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; // pre-multiply final_color *= u_alpha; -} - -// FRAGMENT_SHADER: -uniform vec4 u_widths; -uniform vec4[3] u_outline_rect; - -_IN_ vec4 final_color; - -void main() { - vec4 f = gl_FragCoord; - f.x += u_viewport.x; - f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect outside = create_rect(u_outline_rect); RoundedRect inside = rounded_rect_shrink (outside, u_widths); @@ -28,9 +20,25 @@ void main() { rounded_rect_transform(outside, u_modelview); rounded_rect_transform(inside, u_modelview); - float alpha = clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy), - 0.0, 1.0); + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +uniform vec4[3] u_outline_rect; + +_IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec4 f = gl_FragCoord; + f.x += u_viewport.x; + f.y = (u_viewport.y + u_viewport.w) - f.y; + + float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), + 0.0, 1.0); setOutputColor(final_color * alpha); } diff --git a/gsk/resources/glsl/inset_shadow.glsl b/gsk/resources/glsl/inset_shadow.glsl index 087798abaf..b3ba05a41f 100644 --- a/gsk/resources/glsl/inset_shadow.glsl +++ b/gsk/resources/glsl/inset_shadow.glsl @@ -1,7 +1,12 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,20 +14,6 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; final_color *= u_alpha; -} - -// FRAGMENT_SHADER: -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - -_IN_ vec4 final_color; - -void main() { - vec4 f = gl_FragCoord; - - f.x += u_viewport.x; - f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect outside = create_rect(u_outline_rect); RoundedRect inside = rounded_rect_shrink(outside, vec4(u_spread)); @@ -32,8 +23,23 @@ void main() { rounded_rect_transform(outside, u_modelview); rounded_rect_transform(inside, u_modelview); - float alpha = clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy), + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +_IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec4 f = gl_FragCoord; + + f.x += u_viewport.x; + f.y = (u_viewport.y + u_viewport.w) - f.y; + + float alpha = clamp (rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), 0.0, 1.0); setOutputColor(final_color * alpha); diff --git a/gsk/resources/glsl/outset_shadow.glsl b/gsk/resources/glsl/outset_shadow.glsl index ada444d612..4111ddcea8 100644 --- a/gsk/resources/glsl/outset_shadow.glsl +++ b/gsk/resources/glsl/outset_shadow.glsl @@ -1,7 +1,9 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -12,12 +14,15 @@ void main() { // pre-multiply final_color.rgb *= final_color.a; final_color *= u_alpha; + + RoundedRect outline = create_rect(u_outline_rect); + rounded_rect_transform(outline, u_modelview); + rounded_rect_encode(outline, transformed_outline); } // FRAGMENT_SHADER: -uniform vec4[3] u_outline_rect; - _IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outline; void main() { vec4 f = gl_FragCoord; @@ -25,11 +30,8 @@ void main() { f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; - RoundedRect outline = create_rect(u_outline_rect); - rounded_rect_transform(outline, u_modelview); - float alpha = Texture(u_source, vUv).a; - alpha *= (1.0 - clamp(rounded_rect_coverage(outline, f.xy), 0.0, 1.0)); + alpha *= (1.0 - clamp(rounded_rect_coverage(decode_rect(transformed_outline), f.xy), 0.0, 1.0)); vec4 color = final_color * alpha; diff --git a/gsk/resources/glsl/preamble.fs.glsl b/gsk/resources/glsl/preamble.fs.glsl index 056a4a27b7..b5c958ebf1 100644 --- a/gsk/resources/glsl/preamble.fs.glsl +++ b/gsk/resources/glsl/preamble.fs.glsl @@ -1,11 +1,3 @@ -#ifdef GSK_GL3 -precision highp float; -#endif - -#ifdef GSK_GLES -precision highp float; -#endif - uniform sampler2D u_source; uniform mat4 u_projection; uniform mat4 u_modelview; @@ -14,42 +6,23 @@ uniform vec4 u_viewport; uniform vec4[3] u_clip_rect; #if GSK_GLES -#define _OUT_ varying -#define _IN_ varying #elif GSK_LEGACY -#define _OUT_ varying -#define _IN_ varying _OUT_ vec4 outputColor; #else -#define _OUT_ out -#define _IN_ in _OUT_ vec4 outputColor; #endif + _IN_ vec2 vUv; -struct RoundedRect +RoundedRect decode_rect(_ROUNDED_RECT_UNIFORM_ r) { - vec4 bounds; - // Look, arrays can't be in structs if you want to return the struct - // from a function in gles or whatever. Just kill me. - vec4 corner_points1; // xy = top left, zw = top right - vec4 corner_points2; // xy = bottom right, zw = bottom left -}; - -// Transform from a GskRoundedRect to a RoundedRect as we need it. -RoundedRect -create_rect(vec4[3] data) -{ - vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); - - vec4 corner_points1 = vec4(bounds.xy + data[1].xy, - bounds.zy + vec2(data[1].zw * vec2(-1, 1))); - vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), - bounds.xw + vec2(data[2].zw * vec2(1, -1))); - - return RoundedRect(bounds, corner_points1, corner_points2); +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return RoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif } float @@ -103,45 +76,6 @@ rounded_rect_coverage (RoundedRect r, vec2 p) return 1.0 - dot(vec4(is_out), corner_coverages); } -// amount is: top, right, bottom, left -RoundedRect -rounded_rect_shrink (RoundedRect r, vec4 amount) -{ - vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; - vec4 new_corner_points1 = r.corner_points1; - vec4 new_corner_points2 = r.corner_points2; - - if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; - if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; - if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; - if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; - - return RoundedRect (new_bounds, new_corner_points1, new_corner_points2); -} - -void -rounded_rect_offset(inout RoundedRect r, vec2 offset) -{ - r.bounds.xy += offset; - r.bounds.zw += offset; - r.corner_points1.xy += offset; - r.corner_points1.zw += offset; - r.corner_points2.xy += offset; - r.corner_points2.zw += offset; -} - -void rounded_rect_transform(inout RoundedRect r, mat4 mat) -{ - r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; - r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; - - r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; - r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; - - r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; - r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; -} - vec4 Texture(sampler2D sampler, vec2 texCoords) { #if GSK_GLES return texture2D(sampler, texCoords); diff --git a/gsk/resources/glsl/preamble.glsl b/gsk/resources/glsl/preamble.glsl new file mode 100644 index 0000000000..9dd711cbd2 --- /dev/null +++ b/gsk/resources/glsl/preamble.glsl @@ -0,0 +1,37 @@ +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _ROUNDED_RECT_UNIFORM_ RoundedRect +#endif + + +struct RoundedRect +{ + vec4 bounds; + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a GskRoundedRect to a RoundedRect as we need it. +RoundedRect +create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return RoundedRect(bounds, corner_points1, corner_points2); +} diff --git a/gsk/resources/glsl/preamble.vs.glsl b/gsk/resources/glsl/preamble.vs.glsl index 94c4f276a4..1dc4a5e7bf 100644 --- a/gsk/resources/glsl/preamble.vs.glsl +++ b/gsk/resources/glsl/preamble.vs.glsl @@ -2,26 +2,72 @@ uniform mat4 u_projection; uniform mat4 u_modelview; uniform float u_alpha; -#ifdef GSK_GLES -precision highp float; -#endif - #if GSK_GLES -#define _OUT_ varying -#define _IN_ varying attribute vec2 aPosition; attribute vec2 aUv; _OUT_ vec2 vUv; #elif GSK_LEGACY -#define _OUT_ varying -#define _IN_ varying attribute vec2 aPosition; attribute vec2 aUv; _OUT_ vec2 vUv; #else -#define _OUT_ out -#define _IN_ in _IN_ vec2 aPosition; _IN_ vec2 aUv; _OUT_ vec2 vUv; #endif + +// amount is: top, right, bottom, left +RoundedRect +rounded_rect_shrink (RoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return RoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +rounded_rect_offset(inout RoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void rounded_rect_transform(inout RoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void rounded_rect_encode(RoundedRect r, out _ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif diff --git a/gsk/resources/glsl/unblurred_outset_shadow.glsl b/gsk/resources/glsl/unblurred_outset_shadow.glsl index c5190d392e..77c02be8e1 100644 --- a/gsk/resources/glsl/unblurred_outset_shadow.glsl +++ b/gsk/resources/glsl/unblurred_outset_shadow.glsl @@ -1,7 +1,12 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,20 +14,6 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; final_color *= u_alpha; -} - -// FRAGMENT_SHADER: -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - -_IN_ vec4 final_color; - -void main() { - vec4 f = gl_FragCoord; - - f.x += u_viewport.x; - f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect inside = create_rect(u_outline_rect); RoundedRect outside = rounded_rect_shrink(inside, vec4(- u_spread)); @@ -32,9 +23,24 @@ void main() { rounded_rect_transform(outside, u_modelview); rounded_rect_transform(inside, u_modelview); - float alpha = clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy), - 0.0, 1.0); + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); +} + +// FRAGMENT_SHADER: +_IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; + +void main() { + vec4 f = gl_FragCoord; + + f.x += u_viewport.x; + f.y = (u_viewport.y + u_viewport.w) - f.y; + + float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), + 0.0, 1.0); setOutputColor(final_color * alpha); }