From bbf68c0d9dd2899c6ccffc0ca88df8e8c8d1c26c Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 12:11:26 +0100 Subject: gskglrenderer: Optimize linear-gradient shader --- gsk/gl/gskglrenderer.c | 8 +-- gsk/gl/gskglrenderopsprivate.h | 3 +- gsk/resources/glsl/linear_gradient.glsl | 116 +++++++++++++++++++------------- gsk/resources/glsl/preamble.glsl | 10 +++ 4 files changed, 83 insertions(+), 54 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index c1ef336eed..b083eac5a7 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -3041,8 +3041,9 @@ apply_linear_gradient_op (const Program *program, op->n_color_stops.value * 5, (float *)op->color_stops.value); - glUniform2f (program->linear_gradient.start_point_location, op->start_point[0], op->start_point[1]); - glUniform2f (program->linear_gradient.end_point_location, op->end_point[0], op->end_point[1]); + glUniform4f (program->linear_gradient.points_location, + op->start_point[0], op->start_point[1], + op->end_point[0] - op->start_point[0], op->end_point[1] - op->start_point[1]); } static inline void @@ -3368,8 +3369,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, /* linear gradient */ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, color_stops); INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, num_color_stops); - INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, start_point); - INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, end_point); + INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, points); /* radial gradient */ INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops); diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 24544b0d44..85f62f0451 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -118,8 +118,7 @@ struct _Program struct { int num_color_stops_location; int color_stops_location; - int start_point_location; - int end_point_location; + int points_location; } linear_gradient; struct { int num_color_stops_location; diff --git a/gsk/resources/glsl/linear_gradient.glsl b/gsk/resources/glsl/linear_gradient.glsl index 588d9ec744..aa90b846e0 100644 --- a/gsk/resources/glsl/linear_gradient.glsl +++ b/gsk/resources/glsl/linear_gradient.glsl @@ -1,35 +1,41 @@ // VERTEX_SHADER -uniform vec2 u_start_point; -uniform vec2 u_end_point; -uniform float u_color_stops[6 * 5]; -uniform int u_num_color_stops; +uniform vec4 u_points; -_OUT_ vec2 startPoint; -_OUT_ vec2 endPoint; -_OUT_ float maxDist; -_OUT_ vec2 gradient; -_OUT_ float gradientLength; -_OUT_ vec4 color_stops[6]; -_OUT_ float color_offsets[6]; +_NOPERSPECTIVE_ _OUT_ vec4 info; void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - startPoint = (u_modelview * vec4(u_start_point, 0, 1)).xy; - endPoint = (u_modelview * vec4(u_end_point, 0, 1)).xy; - maxDist = length(endPoint - startPoint); - - // Gradient direction - gradient = endPoint - startPoint; - gradientLength = length(gradient); - - for (int i = 0; i < u_num_color_stops; i ++) { - color_offsets[i] = u_color_stops[(i * 5) + 0]; - color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1], - u_color_stops[(i * 5) + 2], - u_color_stops[(i * 5) + 3], - u_color_stops[(i * 5) + 4])); - } + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_points.xy; + vec2 coord = vec2(dot(mv0, offset), + dot(mv1, offset)); + + // Original equation: + // VS | maxDist = length(end - start); + // VS | gradient = end - start; + // VS | gradientLength = length(gradient); + // FS | pos = frag_coord - start + // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient + // FS | offset = length(proj) / maxDist + + // Simplified formula derivation: + // 1. Notice that maxDist = gradientLength: + // offset = length(proj) / gradientLength + // 2. Let gnorm = gradient / gradientLength, then: + // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) = + // = dot(gnorm, pos) * gnorm + // 3. Since gnorm is unit length then: + // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos) + // 4. We can avoid the FS division by passing a scaled pos from the VS: + // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength) + // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL + vec2 gradient = vec2(dot(mv0, u_points.zw), + dot(mv1, u_points.zw)); + float rcp_gradient_length = inversesqrt(dot(gradient, gradient)); + + info = rcp_gradient_length * vec4(coord, gradient); } // FRAGMENT_SHADER: @@ -39,32 +45,46 @@ uniform int u_num_color_stops; uniform highp int u_num_color_stops; // Why? Because it works like this. #endif -_IN_ vec2 startPoint; -_IN_ vec2 endPoint; -_IN_ float maxDist; -_IN_ vec2 gradient; -_IN_ float gradientLength; -_IN_ vec4 color_stops[6]; -_IN_ float color_offsets[6]; +uniform float u_color_stops[6 * 5]; + +_NOPERSPECTIVE_ _IN_ vec4 info; + +float get_offset(int index) { + return u_color_stops[5 * index]; +} + +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} void main() { - // Position relative to startPoint - vec2 pos = gsk_get_frag_coord() - startPoint; + float offset = dot(info.xy, info.zw); + + if (offset < get_offset(0)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } - // Current pixel, projected onto the line between the start point and the end point - // The projection will be relative to the start point! - vec2 proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient; + int n = u_num_color_stops - 1; + for (int i = 0; i < n; i++) { + float curr_offset = get_offset(i); + float next_offset = get_offset(i + 1); - // Offset of the current pixel - float offset = length(proj) / maxDist; + if (offset >= curr_offset && offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); - vec4 color = color_stops[0]; - for (int i = 1; i < u_num_color_stops; i ++) { - if (offset >= color_offsets[i - 1]) { - float o = (offset - color_offsets[i - 1]) / (color_offsets[i] - color_offsets[i - 1]); - color = mix(color_stops[i - 1], color_stops[i], clamp(o, 0.0, 1.0)); + gskSetOutputColor(color * u_alpha); + return; } } - gskSetOutputColor(color * u_alpha); + gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha)); } diff --git a/gsk/resources/glsl/preamble.glsl b/gsk/resources/glsl/preamble.glsl index 47cc21b004..8ca6469f6d 100644 --- a/gsk/resources/glsl/preamble.glsl +++ b/gsk/resources/glsl/preamble.glsl @@ -5,10 +5,12 @@ precision highp float; #if defined(GSK_GLES) || defined(GSK_LEGACY) #define _OUT_ varying #define _IN_ varying +#define _NOPERSPECTIVE_ #define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] #else #define _OUT_ out #define _IN_ in +#define _NOPERSPECTIVE_ noperspective #define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect #endif @@ -39,3 +41,11 @@ gsk_create_rect(vec4[3] data) vec4 gsk_premultiply(vec4 c) { return vec4(c.rgb * c.a, c.a); } + +vec4 gsk_scaled_premultiply(vec4 c, float s) { + // Fast version of gsk_premultiply(c) * s + // 4 muls instead of 7 + float a = s * c.a; + + return vec4(c.rgb * a, a); +} -- cgit v1.2.1 From 5ac75297717db967d6390207575f4e170c0095d1 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 12:32:04 +0100 Subject: gskglrenderer: Optimize radial-gradient shader --- gsk/gl/gskglrenderer.c | 19 ++++--- gsk/gl/gskglrenderopsprivate.h | 6 +- gsk/resources/glsl/radial_gradient.glsl | 97 ++++++++++++++------------------- 3 files changed, 54 insertions(+), 68 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index b083eac5a7..28df34f348 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -3050,6 +3050,9 @@ static inline void apply_radial_gradient_op (const Program *program, const OpRadialGradient *op) { + float scale; + float bias; + OP_PRINT (" -> Radial gradient"); if (op->n_color_stops.send) glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value); @@ -3059,10 +3062,12 @@ apply_radial_gradient_op (const Program *program, op->n_color_stops.value * 5, (float *)op->color_stops.value); - glUniform1f (program->radial_gradient.start_location, op->start); - glUniform1f (program->radial_gradient.end_location, op->end); - glUniform2f (program->radial_gradient.radius_location, op->radius[0], op->radius[1]); - glUniform2f (program->radial_gradient.center_location, op->center[0], op->center[1]); + scale = 1.0f / (op->end - op->start); + bias = -op->start * scale; + glUniform2f (program->radial_gradient.range_location, scale, bias); + glUniform4f (program->radial_gradient.geometry_location, + op->center[0], op->center[1], + 1.0f / op->radius[0], 1.0f / op->radius[1]); } static inline void @@ -3374,10 +3379,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, /* radial gradient */ INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops); INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops); - INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, center); - INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, start); - INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, end); - INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, radius); + INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry); + INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range); /* conic gradient */ INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops); diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 85f62f0451..a04e1d2b0f 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -123,10 +123,8 @@ struct _Program struct { int num_color_stops_location; int color_stops_location; - int center_location; - int start_location; - int end_location; - int radius_location; + int geometry_location; + int range_location; } radial_gradient; struct { int num_color_stops_location; diff --git a/gsk/resources/glsl/radial_gradient.glsl b/gsk/resources/glsl/radial_gradient.glsl index 178806f83c..9834a69ba4 100644 --- a/gsk/resources/glsl/radial_gradient.glsl +++ b/gsk/resources/glsl/radial_gradient.glsl @@ -1,31 +1,18 @@ // VERTEX_SHADER -uniform float u_start; -uniform float u_end; -uniform float u_color_stops[6 * 5]; -uniform int u_num_color_stops; -uniform vec2 u_radius; -uniform vec2 u_center; +uniform vec4 u_geometry; -_OUT_ vec2 center; -_OUT_ vec4 color_stops[6]; -_OUT_ float color_offsets[6]; -_OUT_ float start; -_OUT_ float end; +_NOPERSPECTIVE_ _OUT_ vec2 coord; void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - center = (u_modelview * vec4(u_center, 0, 1)).xy; - start = u_start; - end = u_end; - - for (int i = 0; i < u_num_color_stops; i ++) { - color_offsets[i] = u_color_stops[(i * 5) + 0]; - color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1], - u_color_stops[(i * 5) + 2], - u_color_stops[(i * 5) + 3], - u_color_stops[(i * 5) + 4])); - } + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + vec2 dir = vec2(dot(mv0, offset), + dot(mv1, offset)); + + coord = dir * u_geometry.zw; } // FRAGMENT_SHADER: @@ -35,50 +22,48 @@ uniform int u_num_color_stops; uniform highp int u_num_color_stops; #endif -uniform vec2 u_radius; -uniform float u_end; +uniform vec2 u_range; +uniform float u_color_stops[6 * 5]; + +_NOPERSPECTIVE_ _IN_ vec2 coord; + +float get_offset(int index) { + return u_color_stops[5 * index]; +} -_IN_ vec2 center; -_IN_ vec4 color_stops[6]; -_IN_ float color_offsets[6]; -_IN_ float start; -_IN_ float end; +vec4 get_color(int index) { + int base = 5 * index + 1; -// The offsets in the color stops are relative to the -// start and end values of the gradient. -float abs_offset(float offset) { - return start + ((end - start) * offset); + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); } void main() { - vec2 pixel = gsk_get_frag_coord(); - vec2 rel = (center - pixel) / (u_radius); - float d = sqrt(dot(rel, rel)); - - if (d < abs_offset (color_offsets[0])) { - gskSetOutputColor(color_stops[0] * u_alpha); - return; - } + // Reverse scale + float offset = length(coord) * u_range.x + u_range.y; - if (d > end) { - gskSetOutputColor(color_stops[u_num_color_stops - 1] * u_alpha); + if (offset < get_offset(0)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); return; } - vec4 color = vec4(0, 0, 0, 0); - for (int i = 1; i < u_num_color_stops; i++) { - float last_offset = abs_offset(color_offsets[i - 1]); - float this_offset = abs_offset(color_offsets[i]); + int n = u_num_color_stops - 1; + for (int i = 0; i < n; i++) { + float curr_offset = get_offset(i); + float next_offset = get_offset(i + 1); - // We have color_stops[i - 1] at last_offset and color_stops[i] at this_offset. - // We now need to map `d` between those two offsets and simply mix linearly between them - if (d >= last_offset && d <= this_offset) { - float f = (d - last_offset) / (this_offset - last_offset); + if (offset >= curr_offset && offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); - color = mix(color_stops[i - 1], color_stops[i], f); - break; + gskSetOutputColor(color * u_alpha); + return; } } - gskSetOutputColor(color * u_alpha); + gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha)); } -- cgit v1.2.1 From b15902bf4486cb49b14d948b974fefc919e46fd5 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 12:40:48 +0100 Subject: gskglrenderer: Optimize conic-gradient shader --- gsk/gl/gskglrenderer.c | 18 +++++-- gsk/gl/gskglrenderopsprivate.h | 3 +- gsk/resources/glsl/conic_gradient.glsl | 94 ++++++++++++++++++---------------- 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 28df34f348..4807dbfba1 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -3074,6 +3074,10 @@ static inline void apply_conic_gradient_op (const Program *program, const OpConicGradient *op) { + float angle; + float bias; + float scale; + OP_PRINT (" -> Conic gradient"); if (op->n_color_stops.send) glUniform1i (program->conic_gradient.num_color_stops_location, op->n_color_stops.value); @@ -3083,8 +3087,15 @@ apply_conic_gradient_op (const Program *program, op->n_color_stops.value * 5, (float *)op->color_stops.value); - glUniform1f (program->conic_gradient.rotation_location, op->rotation); - glUniform2f (program->conic_gradient.center_location, op->center[0], op->center[1]); + angle = 90.0f - op->rotation; + angle = M_PI * angle / 180.0f; + angle = fmodf (angle, 2.0f * M_PI); + if (angle < 0.0f) + angle += 2.0f * M_PI; + + scale = 0.5f * M_1_PI; + bias = angle * scale + 2.0f; + glUniform4f (program->conic_gradient.geometry_location, op->center[0], op->center[1], scale, bias); } static inline void @@ -3385,8 +3396,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, /* conic gradient */ INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops); INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, num_color_stops); - INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, center); - INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, rotation); + INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, geometry); /* blur */ INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius); diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index a04e1d2b0f..ada8ed43b2 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -129,8 +129,7 @@ struct _Program struct { int num_color_stops_location; int color_stops_location; - int center_location; - int rotation_location; + int geometry_location; } conic_gradient; struct { int blur_radius_location; diff --git a/gsk/resources/glsl/conic_gradient.glsl b/gsk/resources/glsl/conic_gradient.glsl index 7f73508a3f..630a42c5e6 100644 --- a/gsk/resources/glsl/conic_gradient.glsl +++ b/gsk/resources/glsl/conic_gradient.glsl @@ -1,34 +1,17 @@ // VERTEX_SHADER -uniform vec2 u_center; -uniform float u_rotation; -uniform float u_color_stops[6 * 5]; -uniform int u_num_color_stops; - -const float PI = 3.1415926535897932384626433832795; +uniform vec4 u_geometry; -_OUT_ vec2 center; -_OUT_ float rotation; -_OUT_ vec4 color_stops[6]; -_OUT_ float color_offsets[6]; +_NOPERSPECTIVE_ _OUT_ vec2 coord; void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - // The -90 is because conics point to the top by default - rotation = mod (u_rotation - 90.0, 360.0); - if (rotation < 0.0) - rotation += 360.0; - rotation = PI / 180.0 * rotation; - - center = (u_modelview * vec4(u_center, 0, 1)).xy; - - for (int i = 0; i < u_num_color_stops; i ++) { - color_offsets[i] = u_color_stops[(i * 5) + 0]; - color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1], - u_color_stops[(i * 5) + 2], - u_color_stops[(i * 5) + 3], - u_color_stops[(i * 5) + 4])); - } + gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); + + vec2 mv0 = u_modelview[0].xy; + vec2 mv1 = u_modelview[1].xy; + vec2 offset = aPosition - u_geometry.xy; + + coord = vec2(dot(mv0, offset), + dot(mv1, offset)); } // FRAGMENT_SHADER: @@ -38,32 +21,53 @@ uniform int u_num_color_stops; uniform highp int u_num_color_stops; // Why? Because it works like this. #endif -const float PI = 3.1415926535897932384626433832795; +uniform vec4 u_geometry; +uniform float u_color_stops[6 * 5]; -_IN_ vec2 center; -_IN_ float rotation; -_IN_ vec4 color_stops[6]; -_IN_ float color_offsets[6]; +_NOPERSPECTIVE_ _IN_ vec2 coord; -void main() { - // Position relative to center - vec2 pos = gsk_get_frag_coord() - center; +float get_offset(int index) { + return u_color_stops[5 * index]; +} +vec4 get_color(int index) { + int base = 5 * index + 1; + + return vec4(u_color_stops[base], + u_color_stops[base + 1], + u_color_stops[base + 2], + u_color_stops[base + 3]); +} + +void main() { // direction of point in range [-PI, PI] - float angle = atan (pos.y, pos.x); - // rotate, it's now [-2 * PI, PI] - angle -= rotation; + vec2 pos = floor(coord); + float angle = atan(pos.y, pos.x); + // fract() does the modulo here, so now we have progress // into the current conic - float offset = fract (angle / 2.0 / PI + 2.0); + float offset = fract(angle * u_geometry.z + u_geometry.w); + + if (offset < get_offset(0)) { + gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); + return; + } + + int n = u_num_color_stops - 1; + for (int i = 0; i < n; i++) { + float curr_offset = get_offset(i); + float next_offset = get_offset(i + 1); + + if (offset >= curr_offset && offset < next_offset) { + float f = (offset - curr_offset) / (next_offset - curr_offset); + vec4 curr_color = gsk_premultiply(get_color(i)); + vec4 next_color = gsk_premultiply(get_color(i + 1)); + vec4 color = mix(curr_color, next_color, f); - vec4 color = color_stops[0]; - for (int i = 1; i < u_num_color_stops; i ++) { - if (offset >= color_offsets[i - 1]) { - float o = (offset - color_offsets[i - 1]) / (color_offsets[i] - color_offsets[i - 1]); - color = mix(color_stops[i - 1], color_stops[i], clamp(o, 0.0, 1.0)); + gskSetOutputColor(color * u_alpha); + return; } } - gskSetOutputColor(color * u_alpha); + gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha)); } -- cgit v1.2.1 From 976a05f6eb55bc37ebb58a1d52f8e015701fe667 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 12:46:22 +0100 Subject: gskglrenderer: First class support of repeating-linear-gradient --- gsk/gl/gskglrenderer.c | 6 +++++- gsk/gl/gskglrenderops.c | 2 ++ gsk/gl/gskglrenderopsprivate.h | 2 ++ gsk/gl/opbuffer.h | 1 + gsk/resources/glsl/linear_gradient.glsl | 5 +++++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 4807dbfba1..026c827ab5 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -1452,6 +1452,7 @@ render_linear_gradient_node (GskGLRenderer *self, ops_set_linear_gradient (builder, n_color_stops, stops, + gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE, builder->dx + start->x, builder->dy + start->y, builder->dx + end->x, @@ -3044,6 +3045,7 @@ apply_linear_gradient_op (const Program *program, glUniform4f (program->linear_gradient.points_location, op->start_point[0], op->start_point[1], op->end_point[0] - op->start_point[0], op->end_point[1] - op->start_point[1]); + glUniform1i (program->linear_gradient.repeat_location, op->repeat); } static inline void @@ -3385,6 +3387,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, /* linear gradient */ INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, color_stops); INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, num_color_stops); + INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, repeat); INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, points); /* radial gradient */ @@ -3742,6 +3745,8 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_LINEAR_GRADIENT_NODE: + /* Intentional fall-through */ + case GSK_REPEATING_LINEAR_GRADIENT_NODE: render_linear_gradient_node (self, node, builder); break; @@ -3812,7 +3817,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, render_gl_shader_node (self, node, builder); break; - case GSK_REPEATING_LINEAR_GRADIENT_NODE: case GSK_REPEATING_RADIAL_GRADIENT_NODE: case GSK_CAIRO_NODE: default: diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index 8bd420e7bd..ec14be1e13 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -859,6 +859,7 @@ void ops_set_linear_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, + bool repeat, float start_x, float start_y, float end_x, @@ -912,6 +913,7 @@ ops_set_linear_gradient (RenderOpBuilder *self, sizeof (GskColorStop) * real_n_color_stops); } + op->repeat = repeat; op->start_point[0] = start_x; op->start_point[1] = start_y; op->end_point[0] = end_x; diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index ada8ed43b2..ccc63ab074 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -119,6 +119,7 @@ struct _Program int num_color_stops_location; int color_stops_location; int points_location; + int repeat_location; } linear_gradient; struct { int num_color_stops_location; @@ -315,6 +316,7 @@ void ops_set_unblurred_outset_shadow (RenderOpBuilder *se void ops_set_linear_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, + bool repeat, float start_x, float start_y, float end_x, diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h index db9b5c9425..4241214a37 100644 --- a/gsk/gl/opbuffer.h +++ b/gsk/gl/opbuffer.h @@ -146,6 +146,7 @@ typedef struct IntUniformValue n_color_stops; float start_point[2]; float end_point[2]; + bool repeat; } OpLinearGradient; typedef struct diff --git a/gsk/resources/glsl/linear_gradient.glsl b/gsk/resources/glsl/linear_gradient.glsl index aa90b846e0..cc90392c06 100644 --- a/gsk/resources/glsl/linear_gradient.glsl +++ b/gsk/resources/glsl/linear_gradient.glsl @@ -46,6 +46,7 @@ uniform highp int u_num_color_stops; // Why? Because it works like this. #endif uniform float u_color_stops[6 * 5]; +uniform bool u_repeat; _NOPERSPECTIVE_ _IN_ vec4 info; @@ -65,6 +66,10 @@ vec4 get_color(int index) { void main() { float offset = dot(info.xy, info.zw); + if (u_repeat) { + offset = fract(offset); + } + if (offset < get_offset(0)) { gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); return; -- cgit v1.2.1 From 04000f28e7579193c3289db5a85283f0ce98e783 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 12:49:16 +0100 Subject: gskglrenderer: First class support of repeating-radial-gradient --- gsk/gl/gskglrenderer.c | 7 ++++++- gsk/gl/gskglrenderops.c | 2 ++ gsk/gl/gskglrenderopsprivate.h | 2 ++ gsk/gl/opbuffer.h | 1 + gsk/resources/glsl/radial_gradient.glsl | 5 +++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 026c827ab5..70c5e57812 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -1486,6 +1486,7 @@ render_radial_gradient_node (GskGLRenderer *self, ops_set_radial_gradient (builder, n_color_stops, stops, + gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE, builder->dx + center->x, builder->dy + center->y, start, end, @@ -3066,6 +3067,8 @@ apply_radial_gradient_op (const Program *program, scale = 1.0f / (op->end - op->start); bias = -op->start * scale; + + glUniform1i (program->radial_gradient.repeat_location, op->repeat); glUniform2f (program->radial_gradient.range_location, scale, bias); glUniform4f (program->radial_gradient.geometry_location, op->center[0], op->center[1], @@ -3393,6 +3396,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, /* radial gradient */ INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops); INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops); + INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, repeat); INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry); INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range); @@ -3751,6 +3755,8 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_RADIAL_GRADIENT_NODE: + /* Intentional fall-through */ + case GSK_REPEATING_RADIAL_GRADIENT_NODE: render_radial_gradient_node (self, node, builder); break; @@ -3817,7 +3823,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, render_gl_shader_node (self, node, builder); break; - case GSK_REPEATING_RADIAL_GRADIENT_NODE: case GSK_CAIRO_NODE: default: { diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index ec14be1e13..ad9518b228 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -924,6 +924,7 @@ void ops_set_radial_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, + bool repeat, float center_x, float center_y, float start, @@ -947,6 +948,7 @@ ops_set_radial_gradient (RenderOpBuilder *self, op->radius[1] = vradius; op->start = start; op->end = end; + op->repeat = repeat; } void diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index ccc63ab074..d556009d06 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -126,6 +126,7 @@ struct _Program int color_stops_location; int geometry_location; int range_location; + int repeat_location; } radial_gradient; struct { int num_color_stops_location; @@ -324,6 +325,7 @@ void ops_set_linear_gradient (RenderOpBuilder *self, void ops_set_radial_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, + bool repeat, float center_x, float center_y, float start, diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h index 4241214a37..a5c1af9189 100644 --- a/gsk/gl/opbuffer.h +++ b/gsk/gl/opbuffer.h @@ -157,6 +157,7 @@ typedef struct float end; float radius[2]; float center[2]; + bool repeat; } OpRadialGradient; typedef struct diff --git a/gsk/resources/glsl/radial_gradient.glsl b/gsk/resources/glsl/radial_gradient.glsl index 9834a69ba4..0ab3fdf07a 100644 --- a/gsk/resources/glsl/radial_gradient.glsl +++ b/gsk/resources/glsl/radial_gradient.glsl @@ -22,6 +22,7 @@ uniform int u_num_color_stops; uniform highp int u_num_color_stops; #endif +uniform bool u_repeat; uniform vec2 u_range; uniform float u_color_stops[6 * 5]; @@ -44,6 +45,10 @@ void main() { // Reverse scale float offset = length(coord) * u_range.x + u_range.y; + if (u_repeat) { + offset = fract(offset); + } + if (offset < get_offset(0)) { gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); return; -- cgit v1.2.1 From 1b698c896eccb2997388c477012216029a935318 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 14:57:02 +0100 Subject: gskglrenderer: Use gboolean instead of bool --- gsk/gl/gskglrenderops.c | 4 ++-- gsk/gl/gskglrenderopsprivate.h | 4 ++-- gsk/gl/opbuffer.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index ad9518b228..f5c6ab6e62 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -859,7 +859,7 @@ void ops_set_linear_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, - bool repeat, + gboolean repeat, float start_x, float start_y, float end_x, @@ -924,7 +924,7 @@ void ops_set_radial_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, - bool repeat, + gboolean repeat, float center_x, float center_y, float start, diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index d556009d06..20af58fda5 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -317,7 +317,7 @@ void ops_set_unblurred_outset_shadow (RenderOpBuilder *se void ops_set_linear_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, - bool repeat, + gboolean repeat, float start_x, float start_y, float end_x, @@ -325,7 +325,7 @@ void ops_set_linear_gradient (RenderOpBuilder *self, void ops_set_radial_gradient (RenderOpBuilder *self, guint n_color_stops, const GskColorStop *color_stops, - bool repeat, + gboolean repeat, float center_x, float center_y, float start, diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h index a5c1af9189..e13e8ab2e4 100644 --- a/gsk/gl/opbuffer.h +++ b/gsk/gl/opbuffer.h @@ -146,7 +146,7 @@ typedef struct IntUniformValue n_color_stops; float start_point[2]; float end_point[2]; - bool repeat; + gboolean repeat; } OpLinearGradient; typedef struct @@ -157,7 +157,7 @@ typedef struct float end; float radius[2]; float center[2]; - bool repeat; + gboolean repeat; } OpRadialGradient; typedef struct -- cgit v1.2.1 From 0088f840fed64cdf8672731a3c6414ecc7bc23a6 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Tue, 26 Jan 2021 16:15:12 +0100 Subject: gskrendernode: Cache angle in conic gradients --- gsk/gl/gskglrenderer.c | 13 +++---------- gsk/gl/gskglrenderops.c | 4 ++-- gsk/gl/gskglrenderopsprivate.h | 2 +- gsk/gl/opbuffer.h | 2 +- gsk/gskrendernode.h | 2 ++ gsk/gskrendernodeimpl.c | 27 +++++++++++++++++++++++++++ 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 70c5e57812..3232794539 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -1512,7 +1512,7 @@ render_conic_gradient_node (GskGLRenderer *self, { const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL); const graphene_point_t *center = gsk_conic_gradient_node_get_center (node); - const float rotation = gsk_conic_gradient_node_get_rotation (node); + const float angle = gsk_conic_gradient_node_get_angle (node); ops_set_program (builder, &self->programs->conic_gradient_program); ops_set_conic_gradient (builder, @@ -1520,7 +1520,7 @@ render_conic_gradient_node (GskGLRenderer *self, stops, builder->dx + center->x, builder->dy + center->y, - rotation); + angle); load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); } @@ -3079,7 +3079,6 @@ static inline void apply_conic_gradient_op (const Program *program, const OpConicGradient *op) { - float angle; float bias; float scale; @@ -3092,14 +3091,8 @@ apply_conic_gradient_op (const Program *program, op->n_color_stops.value * 5, (float *)op->color_stops.value); - angle = 90.0f - op->rotation; - angle = M_PI * angle / 180.0f; - angle = fmodf (angle, 2.0f * M_PI); - if (angle < 0.0f) - angle += 2.0f * M_PI; - scale = 0.5f * M_1_PI; - bias = angle * scale + 2.0f; + bias = op->angle * scale + 2.0f; glUniform4f (program->conic_gradient.geometry_location, op->center[0], op->center[1], scale, bias); } diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index f5c6ab6e62..36f7e37e35 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -957,7 +957,7 @@ ops_set_conic_gradient (RenderOpBuilder *self, const GskColorStop *color_stops, float center_x, float center_y, - float rotation) + float angle) { const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops); OpConicGradient *op; @@ -971,6 +971,6 @@ ops_set_conic_gradient (RenderOpBuilder *self, op->color_stops.send = true; op->center[0] = center_x; op->center[1] = center_y; - op->rotation = rotation; + op->angle = angle; } diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 20af58fda5..b23060014b 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -337,7 +337,7 @@ void ops_set_conic_gradient (RenderOpBuilder *self, const GskColorStop *color_stops, float center_x, float center_y, - float rotation); + float angle); GskQuadVertex * ops_draw (RenderOpBuilder *builder, const GskQuadVertex vertex_data[GL_N_VERTICES]); diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h index e13e8ab2e4..ea954249c5 100644 --- a/gsk/gl/opbuffer.h +++ b/gsk/gl/opbuffer.h @@ -165,7 +165,7 @@ typedef struct ColorStopUniformValue color_stops; IntUniformValue n_color_stops; float center[2]; - float rotation; + float angle; } OpConicGradient; typedef struct diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 99af00286f..5ae6bf2f89 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -257,6 +257,8 @@ const graphene_point_t * gsk_conic_gradient_node_get_center (GskRenderNo GDK_AVAILABLE_IN_ALL float gsk_conic_gradient_node_get_rotation (GskRenderNode *node); GDK_AVAILABLE_IN_ALL +float gsk_conic_gradient_node_get_angle (GskRenderNode *node); +GDK_AVAILABLE_IN_ALL gsize gsk_conic_gradient_node_get_n_color_stops (GskRenderNode *node); GDK_AVAILABLE_IN_ALL const GskColorStop * gsk_conic_gradient_node_get_color_stops (GskRenderNode *node, diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index fb6c659baf..f932c38185 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -782,6 +782,7 @@ struct _GskConicGradientNode graphene_point_t center; float rotation; + float angle; gsize n_stops; GskColorStop *stops; @@ -1023,6 +1024,12 @@ gsk_conic_gradient_node_new (const graphene_rect_t *bounds, self->stops = g_malloc_n (n_color_stops, sizeof (GskColorStop)); memcpy (self->stops, color_stops, n_color_stops * sizeof (GskColorStop)); + self->angle = 90.f - self->rotation; + self->angle = G_PI * self->angle / 180.f; + self->angle = fmodf (self->angle, 2.f * G_PI); + if (self->angle < 0.f) + self->angle += 2.f * G_PI; + return node; } @@ -1095,6 +1102,26 @@ gsk_conic_gradient_node_get_rotation (GskRenderNode *node) return self->rotation; } +/** + * gsk_conic_gradient_node_get_angle: + * @node: (type GskConicGradientNode): a #GskRenderNode for a conic gradient + * + * Retrieves the angle for the gradient in radians, normalized in [0, 2 * PI] + * + * The angle is starting at the top and going clockwise, as expressed + * in the css specification: + * angle = 90 - gsk_conic_gradient_node_get_rotation() + * + * Returns: the angle for the gradient + */ +float +gsk_conic_gradient_node_get_angle (GskRenderNode *node) +{ + GskConicGradientNode *self = (GskConicGradientNode *) node; + + return self->angle; +} + /*** GSK_BORDER_NODE ***/ /** -- cgit v1.2.1 From a1dd6521e8310fd81073aa5282465092ff182d80 Mon Sep 17 00:00:00 2001 From: Fabio Lagalla Date: Wed, 27 Jan 2021 12:52:11 +0100 Subject: gskglrenderer: Remove switch fallthrough comments --- gsk/gl/gskglrenderer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 3232794539..7f1aa2c6cd 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -3742,13 +3742,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_LINEAR_GRADIENT_NODE: - /* Intentional fall-through */ case GSK_REPEATING_LINEAR_GRADIENT_NODE: render_linear_gradient_node (self, node, builder); break; case GSK_RADIAL_GRADIENT_NODE: - /* Intentional fall-through */ case GSK_REPEATING_RADIAL_GRADIENT_NODE: render_radial_gradient_node (self, node, builder); break; -- cgit v1.2.1