[gtk/wip/baedert/radial-gradient: 126/126] gl renderer: Add radial gradient shader
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/baedert/radial-gradient: 126/126] gl renderer: Add radial gradient shader
- Date: Fri, 18 Sep 2020 12:49:56 +0000 (UTC)
commit 4f2d44c4f1acdada89d13af6fb93d8050c87547d
Author: Timm Bäder <mail baedert org>
Date: Fri Sep 18 14:42:36 2020 +0200
gl renderer: Add radial gradient shader
gsk/gl/gskglrenderer.c | 63 ++++++++++++++++++++++-
gsk/gl/gskglrenderops.c | 29 +++++++++++
gsk/gl/gskglrenderopsprivate.h | 28 ++++++++++-
gsk/gl/opbuffer.c | 1 +
gsk/gl/opbuffer.h | 41 +++++++++------
gsk/gskrendernodeimpl.c | 2 -
gsk/meson.build | 1 +
gsk/resources/glsl/radial_gradient.glsl | 89 +++++++++++++++++++++++++++++++++
8 files changed, 235 insertions(+), 19 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 00fb5aea5e..96aecbd70b 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1192,6 +1192,32 @@ render_linear_gradient_node (GskGLRenderer *self,
load_vertex_data (ops_draw (builder, NULL), node, builder);
}
+static inline void
+render_radial_gradient_node (GskGLRenderer *self,
+ GskRenderNode *node,
+ RenderOpBuilder *builder)
+{
+ const float scale = ops_get_scale (builder);
+ const int n_color_stops = MIN (8, gsk_radial_gradient_node_get_n_color_stops (node));
+ const GskColorStop *stops = gsk_radial_gradient_node_peek_color_stops (node, NULL);
+ const graphene_point_t *center = gsk_radial_gradient_node_peek_center (node);
+ const float start = gsk_radial_gradient_node_get_start (node);
+ const float end = gsk_radial_gradient_node_get_end (node);
+ const float hradius = gsk_radial_gradient_node_get_hradius (node);
+ const float vradius = gsk_radial_gradient_node_get_vradius (node);
+
+ ops_set_program (builder, &self->programs->radial_gradient_program);
+ ops_set_radial_gradient (builder,
+ n_color_stops,
+ stops,
+ builder->dx + center->x,
+ builder->dy + center->y,
+ start, end,
+ hradius * scale, vradius * scale);
+
+ load_vertex_data (ops_draw (builder, NULL), node, builder);
+}
+
static inline gboolean
rounded_inner_rect_contains_rect (const GskRoundedRect *rounded,
const graphene_rect_t *rect)
@@ -2761,6 +2787,25 @@ apply_linear_gradient_op (const Program *program,
glUniform2f (program->linear_gradient.end_point_location, op->end_point[0], op->end_point[1]);
}
+static inline void
+apply_radial_gradient_op (const Program *program,
+ const OpRadialGradient *op)
+{
+ OP_PRINT (" -> Radial gradient");
+ if (op->n_color_stops.send)
+ glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value);
+
+ if (op->color_stops.send)
+ glUniform1fv (program->radial_gradient.color_stops_location,
+ 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]);
+}
+
static inline void
apply_border_op (const Program *program,
const OpBorder *op)
@@ -2903,6 +2948,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
{ "/org/gtk/libgsk/glsl/cross_fade.glsl", "cross fade" },
{ "/org/gtk/libgsk/glsl/inset_shadow.glsl", "inset shadow" },
{ "/org/gtk/libgsk/glsl/linear_gradient.glsl", "linear gradient" },
+ { "/org/gtk/libgsk/glsl/radial_gradient.glsl", "radial gradient" },
{ "/org/gtk/libgsk/glsl/outset_shadow.glsl", "outset shadow" },
{ "/org/gtk/libgsk/glsl/repeat.glsl", "repeat" },
{ "/org/gtk/libgsk/glsl/unblurred_outset_shadow.glsl", "unblurred_outset shadow" },
@@ -2984,6 +3030,14 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, start_point);
INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient, end_point);
+ /* 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);
+
/* blur */
INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
@@ -3332,6 +3386,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
render_linear_gradient_node (self, node, builder);
break;
+ case GSK_RADIAL_GRADIENT_NODE:
+ render_radial_gradient_node (self, node, builder);
+ break;
+
case GSK_CLIP_NODE:
render_clip_node (self, node, builder);
break;
@@ -3388,7 +3446,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
- case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CAIRO_NODE:
default:
@@ -3684,6 +3741,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
apply_linear_gradient_op (program, ptr);
break;
+ case OP_CHANGE_RADIAL_GRADIENT:
+ apply_radial_gradient_op (program, ptr);
+ break;
+
case OP_CHANGE_BLUR:
apply_blur_op (program, ptr);
break;
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index 1d48112804..7713f294eb 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -960,3 +960,32 @@ ops_set_linear_gradient (RenderOpBuilder *self,
op->end_point[0] = end_x;
op->end_point[1] = end_y;
}
+
+void
+ops_set_radial_gradient (RenderOpBuilder *self,
+ guint n_color_stops,
+ const GskColorStop *color_stops,
+ float center_x,
+ float center_y,
+ float start,
+ float end,
+ float hradius,
+ float vradius)
+{
+ const guint real_n_color_stops = MIN (MAX_GRADIENT_STOPS, n_color_stops);
+ OpRadialGradient *op;
+
+ /* TODO: State tracking? */
+
+ op = ops_begin (self, OP_CHANGE_RADIAL_GRADIENT);
+ op->n_color_stops.value = real_n_color_stops;
+ op->n_color_stops.send = true;
+ op->color_stops.value = color_stops;
+ op->color_stops.send = true;
+ op->center[0] = center_x;
+ op->center[1] = center_y;
+ op->radius[0] = hradius;
+ op->radius[1] = vradius;
+ op->start = start;
+ op->end = end;
+}
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index ebb39e355a..a6c6d0f232 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -13,7 +13,7 @@
#include "opbuffer.h"
#define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 13
+#define GL_N_PROGRAMS 14
#define MAX_GRADIENT_STOPS 8
typedef struct
@@ -62,6 +62,14 @@ struct _Program
int start_point_location;
int end_point_location;
} linear_gradient;
+ struct {
+ int num_color_stops_location;
+ int color_stops_location;
+ int center_location;
+ int start_location;
+ int end_location;
+ int radius_location;
+ } radial_gradient;
struct {
int blur_radius_location;
int blur_size_location;
@@ -143,6 +151,14 @@ typedef struct
float start_point[2];
float end_point[2];
} linear_gradient;
+ struct {
+ int n_color_stops;
+ GskColorStop color_stops[MAX_GRADIENT_STOPS];
+ float center[2];
+ float start;
+ float end;
+ float radius[2]; /* h/v */
+ } radial_gradient;
};
} ProgramState;
@@ -161,6 +177,7 @@ typedef struct {
Program cross_fade_program;
Program inset_shadow_program;
Program linear_gradient_program;
+ Program radial_gradient_program;
Program outset_shadow_program;
Program repeat_program;
Program unblurred_outset_shadow_program;
@@ -278,6 +295,15 @@ void ops_set_linear_gradient (RenderOpBuilder *self,
float start_y,
float end_x,
float end_y);
+void ops_set_radial_gradient (RenderOpBuilder *self,
+ guint n_color_stops,
+ const GskColorStop *color_stops,
+ float center_x,
+ float center_y,
+ float start,
+ float end,
+ float hradius,
+ float vradius);
GskQuadVertex * ops_draw (RenderOpBuilder *builder,
const GskQuadVertex vertex_data[GL_N_VERTICES]);
diff --git a/gsk/gl/opbuffer.c b/gsk/gl/opbuffer.c
index 496308c5ae..f212e96eec 100644
--- a/gsk/gl/opbuffer.c
+++ b/gsk/gl/opbuffer.c
@@ -15,6 +15,7 @@ static guint op_sizes[OP_LAST] = {
sizeof (OpTexture),
sizeof (OpRepeat),
sizeof (OpLinearGradient),
+ sizeof (OpRadialGradient),
sizeof (OpColorMatrix),
sizeof (OpBlur),
sizeof (OpShadow),
diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h
index 9604f4b852..dcdedc6c50 100644
--- a/gsk/gl/opbuffer.h
+++ b/gsk/gl/opbuffer.h
@@ -23,21 +23,22 @@ typedef enum
OP_CHANGE_SOURCE_TEXTURE = 9,
OP_CHANGE_REPEAT = 10,
OP_CHANGE_LINEAR_GRADIENT = 11,
- OP_CHANGE_COLOR_MATRIX = 12,
- OP_CHANGE_BLUR = 13,
- OP_CHANGE_INSET_SHADOW = 14,
- OP_CHANGE_OUTSET_SHADOW = 15,
- OP_CHANGE_BORDER = 16,
- OP_CHANGE_BORDER_COLOR = 17,
- OP_CHANGE_BORDER_WIDTH = 18,
- OP_CHANGE_CROSS_FADE = 19,
- OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 20,
- OP_CLEAR = 21,
- OP_DRAW = 22,
- OP_DUMP_FRAMEBUFFER = 23,
- OP_PUSH_DEBUG_GROUP = 24,
- OP_POP_DEBUG_GROUP = 25,
- OP_CHANGE_BLEND = 26,
+ OP_CHANGE_RADIAL_GRADIENT = 12,
+ OP_CHANGE_COLOR_MATRIX = 13,
+ OP_CHANGE_BLUR = 14,
+ OP_CHANGE_INSET_SHADOW = 15,
+ OP_CHANGE_OUTSET_SHADOW = 16,
+ OP_CHANGE_BORDER = 17,
+ OP_CHANGE_BORDER_COLOR = 18,
+ OP_CHANGE_BORDER_WIDTH = 19,
+ OP_CHANGE_CROSS_FADE = 20,
+ OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 21,
+ OP_CLEAR = 22,
+ OP_DRAW = 23,
+ OP_DUMP_FRAMEBUFFER = 24,
+ OP_PUSH_DEBUG_GROUP = 25,
+ OP_POP_DEBUG_GROUP = 26,
+ OP_CHANGE_BLEND = 27,
OP_LAST
} OpKind;
@@ -137,6 +138,16 @@ typedef struct
float end_point[2];
} OpLinearGradient;
+typedef struct
+{
+ ColorStopUniformValue color_stops;
+ IntUniformValue n_color_stops;
+ float start;
+ float end;
+ float radius[2];
+ float center[2];
+} OpRadialGradient;
+
typedef struct
{
const graphene_matrix_t *matrix;
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index e383ef88be..efb49738b9 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -394,8 +394,6 @@ struct _GskRadialGradientNode
graphene_point_t center;
- gboolean circle;
-
float hradius;
float vradius;
float start;
diff --git a/gsk/meson.build b/gsk/meson.build
index 9cc22359cb..c3567d78ed 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/radial_gradient.glsl',
'resources/glsl/color_matrix.glsl',
'resources/glsl/blur.glsl',
'resources/glsl/inset_shadow.glsl',
diff --git a/gsk/resources/glsl/radial_gradient.glsl b/gsk/resources/glsl/radial_gradient.glsl
new file mode 100644
index 0000000000..84673fc470
--- /dev/null
+++ b/gsk/resources/glsl/radial_gradient.glsl
@@ -0,0 +1,89 @@
+// VERTEX_SHADER
+uniform float u_start;
+uniform float u_end;
+uniform float u_color_stops[8 * 5];
+uniform int u_num_color_stops;
+uniform vec2 u_radius;
+uniform vec2 u_center;
+
+_OUT_ vec2 center;
+_OUT_ vec4 color_stops[8];
+_OUT_ float color_offsets[8];
+_OUT_ float start;
+_OUT_ float end;
+
+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].r = u_color_stops[(i * 5) + 1];
+ color_stops[i].g = u_color_stops[(i * 5) + 2];
+ color_stops[i].b = u_color_stops[(i * 5) + 3];
+ color_stops[i].a = u_color_stops[(i * 5) + 4];
+ }
+}
+
+// FRAGMENT_SHADER:
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops;
+#endif
+
+uniform vec2 u_radius;
+uniform float u_end;
+
+_IN_ vec2 center;
+_IN_ vec4 color_stops[8];
+_IN_ float color_offsets[8];
+_IN_ float start;
+_IN_ float end;
+
+// 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);
+}
+
+vec4 premultiply(vec4 c) {
+ vec4 k = vec4(c.rgb * c.a, c.a);
+ return k;
+}
+
+void main() {
+ vec2 pixel = get_frag_coord();
+ vec2 rel = (center - pixel) / (u_radius);
+ float d = sqrt(dot(rel, rel));
+
+ if (d < abs_offset (color_offsets[0])) {
+ setOutputColor(premultiply(color_stops[0]) * u_alpha);
+ return;
+ }
+
+ if (d > end) {
+ setOutputColor(premultiply(color_stops[u_num_color_stops - 1]) * 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]);
+
+ // 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);
+
+ color = mix(color_stops[i - 1], color_stops[i], f);
+ break;
+ }
+ }
+
+ setOutputColor(premultiply(color) * u_alpha);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]