summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-03-09 22:29:22 -0500
committerMatthias Clasen <mclasen@redhat.com>2021-03-10 08:44:32 -0500
commitb9d21f1f1a68ad87e5801afed8c5e7405c5975c1 (patch)
tree5e4ad9feb6eebb66b01b7f866cbe0b84d4cf9335
parent8baf29063cc41f555f3f45ce5c7f64ec43ed025e (diff)
downloadgtk+-ngl-tweaks.tar.gz
ngl: Add a shader for short linear gradientsngl-tweaks
Almost all our linear gradients have 2 stops. Add a simple shader for that case.
-rw-r--r--gsk/meson.build1
-rw-r--r--gsk/ngl/gsknglprograms.defs6
-rw-r--r--gsk/ngl/gsknglrenderjob.c35
-rw-r--r--gsk/resources/glsl/linear_gradient_2.glsl84
4 files changed, 125 insertions, 1 deletions
diff --git a/gsk/meson.build b/gsk/meson.build
index dd1ac34ff9..1d579ab5ae 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -7,6 +7,7 @@ gsk_private_gl_shaders = [
'resources/glsl/coloring.glsl',
'resources/glsl/color.glsl',
'resources/glsl/linear_gradient.glsl',
+ 'resources/glsl/linear_gradient_2.glsl',
'resources/glsl/radial_gradient.glsl',
'resources/glsl/conic_gradient.glsl',
'resources/glsl/color_matrix.glsl',
diff --git a/gsk/ngl/gsknglprograms.defs b/gsk/ngl/gsknglprograms.defs
index b0b797f0e9..cfd5580037 100644
--- a/gsk/ngl/gsknglprograms.defs
+++ b/gsk/ngl/gsknglprograms.defs
@@ -57,6 +57,12 @@ GSK_NGL_DEFINE_PROGRAM (linear_gradient,
GSK_NGL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
GSK_NGL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
+GSK_NGL_DEFINE_PROGRAM (linear_gradient_2,
+ "/org/gtk/libgsk/glsl/linear_gradient_2.glsl",
+ GSK_NGL_ADD_UNIFORM (1, LINEAR_GRADIENT_2_COLOR_STOPS, u_color_stops)
+ GSK_NGL_ADD_UNIFORM (2, LINEAR_GRADIENT_2_POINTS, u_points)
+ GSK_NGL_ADD_UNIFORM (3, LINEAR_GRADIENT_2_REPEAT, u_repeat))
+
GSK_NGL_DEFINE_PROGRAM (outset_shadow,
"/org/gtk/libgsk/glsl/outset_shadow.glsl",
GSK_NGL_ADD_UNIFORM (1, OUTSET_SHADOW_COLOR, u_color)
diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c
index 794086c4e3..b34692b3cb 100644
--- a/gsk/ngl/gsknglrenderjob.c
+++ b/gsk/ngl/gsknglrenderjob.c
@@ -1494,6 +1494,37 @@ gsk_ngl_render_job_visit_linear_gradient_node (GskNglRenderJob *job,
}
static inline void
+gsk_ngl_render_job_visit_linear_gradient_2_node (GskNglRenderJob *job,
+ const GskRenderNode *node)
+{
+ const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL);
+ const graphene_point_t *start = gsk_linear_gradient_node_get_start (node);
+ const graphene_point_t *end = gsk_linear_gradient_node_get_end (node);
+ int n_color_stops = gsk_linear_gradient_node_get_n_color_stops (node);
+ gboolean repeat = gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE;
+ float x1 = job->offset_x + start->x;
+ float x2 = job->offset_x + end->x;
+ float y1 = job->offset_y + start->y;
+ float y2 = job->offset_y + end->y;
+
+ g_assert (n_color_stops == 2);
+
+ gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, linear_gradient_2));
+ gsk_ngl_program_set_uniform1fv (job->current_program,
+ UNIFORM_LINEAR_GRADIENT_2_COLOR_STOPS, 0,
+ n_color_stops * 5,
+ (const float *)stops);
+ gsk_ngl_program_set_uniform4f (job->current_program,
+ UNIFORM_LINEAR_GRADIENT_2_POINTS, 0,
+ x1, y1, x2 - x1, y2 - y1);
+ gsk_ngl_program_set_uniform1i (job->current_program,
+ UNIFORM_LINEAR_GRADIENT_2_REPEAT, 0,
+ repeat);
+ gsk_ngl_render_job_draw_rect (job, &node->bounds);
+ gsk_ngl_render_job_end_draw (job);
+}
+
+static inline void
gsk_ngl_render_job_visit_conic_gradient_node (GskNglRenderJob *job,
const GskRenderNode *node)
{
@@ -3695,7 +3726,9 @@ gsk_ngl_render_job_visit_node (GskNglRenderJob *job,
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
- if (gsk_linear_gradient_node_get_n_color_stops (node) < MAX_GRADIENT_STOPS)
+ if (gsk_linear_gradient_node_get_n_color_stops (node) == 2)
+ gsk_ngl_render_job_visit_linear_gradient_2_node (job, node);
+ else if (gsk_linear_gradient_node_get_n_color_stops (node) < MAX_GRADIENT_STOPS)
gsk_ngl_render_job_visit_linear_gradient_node (job, node);
else
gsk_ngl_render_job_visit_as_fallback (job, node);
diff --git a/gsk/resources/glsl/linear_gradient_2.glsl b/gsk/resources/glsl/linear_gradient_2.glsl
new file mode 100644
index 0000000000..b4cc0fb7b2
--- /dev/null
+++ b/gsk/resources/glsl/linear_gradient_2.glsl
@@ -0,0 +1,84 @@
+// VERTEX_SHADER
+uniform vec4 u_points;
+
+_NOPERSPECTIVE_ _OUT_ vec4 info;
+
+void main() {
+ 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:
+uniform float u_color_stops[2 * 5];
+uniform bool u_repeat;
+
+_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() {
+ float offset = dot(info.xy, info.zw);
+
+ if (u_repeat) {
+ offset = fract(offset);
+ }
+
+ float offset0 = get_offset(0);
+ float offset1 = get_offset(1);
+
+ if (offset < offset0) {
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
+ }
+ else if (offset < offset1) {
+ float f = (offset - offset0) / (offset1 - offset0);
+ vec4 curr_color = gsk_premultiply(get_color(0));
+ vec4 next_color = gsk_premultiply(get_color(1));
+ vec4 color = mix(curr_color, next_color, f);
+ gskSetOutputColor(color * u_alpha);
+ return;
+ }
+ else {
+ gskSetOutputColor(gsk_scaled_premultiply(get_color(1), u_alpha));
+ }
+}