summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2020-12-03 06:02:18 +0100
committerBenjamin Otte <otte@redhat.com>2020-12-03 13:07:17 +0100
commit2c1bd399d25e41fa6987df5f8c731b034568e0cc (patch)
tree10d4715a76f59e258e30207ad6333f82af3aa0a3
parentfac5fba0dcc6babd26cdecd39004eec249618675 (diff)
downloadgtk+-wip/otte/conic.tar.gz
glrenderer: Implement a shader for conic gradientswip/otte/conic
-rw-r--r--gsk/gl/gskglrenderer.c62
-rw-r--r--gsk/gl/gskglrenderops.c24
-rw-r--r--gsk/gl/gskglrenderopsprivate.h15
-rw-r--r--gsk/gl/opbuffer.c1
-rw-r--r--gsk/gl/opbuffer.h9
-rw-r--r--gsk/meson.build1
-rw-r--r--gsk/resources/glsl/conic_gradient.glsl69
7 files changed, 179 insertions, 2 deletions
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 57b0767772..6e77194eb4 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1483,6 +1483,35 @@ render_radial_gradient_node (GskGLRenderer *self,
}
}
+static inline void
+render_conic_gradient_node (GskGLRenderer *self,
+ GskRenderNode *node,
+ RenderOpBuilder *builder)
+{
+ const int n_color_stops = gsk_conic_gradient_node_get_n_color_stops (node);
+
+ if (n_color_stops < GL_MAX_GRADIENT_STOPS)
+ {
+ 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);
+
+ ops_set_program (builder, &self->programs->conic_gradient_program);
+ ops_set_conic_gradient (builder,
+ n_color_stops,
+ stops,
+ builder->dx + center->x,
+ builder->dy + center->y,
+ rotation);
+
+ load_vertex_data (ops_draw (builder, NULL), &node->bounds, builder);
+ }
+ else
+ {
+ render_fallback_node (self, node, builder);
+ }
+}
+
static inline gboolean
rounded_inner_rect_contains_rect (const GskRoundedRect *rounded,
const graphene_rect_t *rect)
@@ -3017,6 +3046,23 @@ apply_radial_gradient_op (const Program *program,
}
static inline void
+apply_conic_gradient_op (const Program *program,
+ const OpConicGradient *op)
+{
+ OP_PRINT (" -> Conic gradient");
+ if (op->n_color_stops.send)
+ glUniform1i (program->conic_gradient.num_color_stops_location, op->n_color_stops.value);
+
+ if (op->color_stops.send)
+ glUniform1fv (program->conic_gradient.color_stops_location,
+ 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]);
+}
+
+static inline void
apply_border_op (const Program *program,
const OpBorder *op)
{
@@ -3250,6 +3296,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
{ "/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/conic_gradient.glsl", "conic 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" },
@@ -3312,6 +3359,12 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, end);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, radius);
+ /* 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);
+
/* blur */
INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_radius);
INIT_PROGRAM_UNIFORM_LOCATION (blur, blur_size);
@@ -3663,6 +3716,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
render_radial_gradient_node (self, node, builder);
break;
+ case GSK_CONIC_GRADIENT_NODE:
+ render_conic_gradient_node (self, node, builder);
+ break;
+
case GSK_CLIP_NODE:
render_clip_node (self, node, builder);
break;
@@ -3724,7 +3781,6 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
- case GSK_CONIC_GRADIENT_NODE:
case GSK_CAIRO_NODE:
default:
{
@@ -4027,6 +4083,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
apply_radial_gradient_op (program, ptr);
break;
+ case OP_CHANGE_CONIC_GRADIENT:
+ apply_conic_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 63273db93d..7351cf8746 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -1038,3 +1038,27 @@ ops_set_radial_gradient (RenderOpBuilder *self,
op->start = start;
op->end = end;
}
+
+void
+ops_set_conic_gradient (RenderOpBuilder *self,
+ guint n_color_stops,
+ const GskColorStop *color_stops,
+ float center_x,
+ float center_y,
+ float rotation)
+{
+ const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
+ OpConicGradient *op;
+
+ /* TODO: State tracking? */
+
+ op = ops_begin (self, OP_CHANGE_CONIC_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->rotation = rotation;
+}
+
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 7119ae0680..3dd3cb3411 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 14
+#define GL_N_PROGRAMS 15
#define GL_MAX_GRADIENT_STOPS 6
typedef struct
@@ -130,6 +130,12 @@ struct _Program
int radius_location;
} radial_gradient;
struct {
+ int num_color_stops_location;
+ int color_stops_location;
+ int center_location;
+ int rotation_location;
+ } conic_gradient;
+ struct {
int blur_radius_location;
int blur_size_location;
int blur_dir_location;
@@ -193,6 +199,7 @@ typedef struct {
Program inset_shadow_program;
Program linear_gradient_program;
Program radial_gradient_program;
+ Program conic_gradient_program;
Program outset_shadow_program;
Program repeat_program;
Program unblurred_outset_shadow_program;
@@ -327,6 +334,12 @@ void ops_set_radial_gradient (RenderOpBuilder *self,
float end,
float hradius,
float vradius);
+void ops_set_conic_gradient (RenderOpBuilder *self,
+ guint n_color_stops,
+ const GskColorStop *color_stops,
+ float center_x,
+ float center_y,
+ float rotation);
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 8a7f8c9b1f..806b8f7ca4 100644
--- a/gsk/gl/opbuffer.c
+++ b/gsk/gl/opbuffer.c
@@ -33,6 +33,7 @@ static guint op_sizes[OP_LAST] = {
sizeof (OpBlend),
sizeof (OpGLShader),
sizeof (OpExtraTexture),
+ sizeof (OpConicGradient),
};
void
diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h
index a2236dd7a1..08f48b7c5f 100644
--- a/gsk/gl/opbuffer.h
+++ b/gsk/gl/opbuffer.h
@@ -41,6 +41,7 @@ typedef enum
OP_CHANGE_BLEND = 27,
OP_CHANGE_GL_SHADER_ARGS = 28,
OP_CHANGE_EXTRA_SOURCE_TEXTURE = 29,
+ OP_CHANGE_CONIC_GRADIENT = 30,
OP_LAST
} OpKind;
@@ -158,6 +159,14 @@ typedef struct
typedef struct
{
+ ColorStopUniformValue color_stops;
+ IntUniformValue n_color_stops;
+ float center[2];
+ float rotation;
+} OpConicGradient;
+
+typedef struct
+{
const graphene_matrix_t *matrix;
Vec4UniformValue offset;
} OpColorMatrix;
diff --git a/gsk/meson.build b/gsk/meson.build
index 4ea6091a94..01c5e58fcc 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -8,6 +8,7 @@ gsk_private_gl_shaders = [
'resources/glsl/color.glsl',
'resources/glsl/linear_gradient.glsl',
'resources/glsl/radial_gradient.glsl',
+ 'resources/glsl/conic_gradient.glsl',
'resources/glsl/color_matrix.glsl',
'resources/glsl/blur.glsl',
'resources/glsl/inset_shadow.glsl',
diff --git a/gsk/resources/glsl/conic_gradient.glsl b/gsk/resources/glsl/conic_gradient.glsl
new file mode 100644
index 0000000000..e9dee73e07
--- /dev/null
+++ b/gsk/resources/glsl/conic_gradient.glsl
@@ -0,0 +1,69 @@
+// 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;
+
+_OUT_ vec2 center;
+_OUT_ float rotation;
+_OUT_ vec4 color_stops[6];
+_OUT_ float color_offsets[6];
+
+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, 360.0);
+ if (rotation < 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]));
+ }
+}
+
+// FRAGMENT_SHADER:
+#ifdef GSK_LEGACY
+uniform int u_num_color_stops;
+#else
+uniform highp int u_num_color_stops; // Why? Because it works like this.
+#endif
+
+const float PI = 3.1415926535897932384626433832795;
+
+_IN_ vec2 center;
+_IN_ float rotation;
+_IN_ vec4 color_stops[6];
+_IN_ float color_offsets[6];
+
+void main() {
+ // Position relative to center
+ vec2 pos = gsk_get_frag_coord() - center;
+
+ // direction of point in range [-PI, PI]
+ float angle = atan (pos.y, pos.x);
+ // rotate, it's now [-2 * PI, PI]
+ angle -= rotation;
+ // fract() does the modulo here, so now we have progress
+ // into the current conic
+ float offset = fract (angle / 2 / PI + 2);
+
+ 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);
+}