[gtk+/wip/baedert/gl: 163/177] gl renderer: Implement simple border nodes
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/baedert/gl: 163/177] gl renderer: Implement simple border nodes
- Date: Tue, 5 Dec 2017 12:56:12 +0000 (UTC)
commit 151752d274c4c18c00b4f2ec74a6c814ac5b8aa1
Author: Timm Bäder <mail baedert org>
Date: Fri Dec 1 11:55:10 2017 +0100
gl renderer: Implement simple border nodes
gsk/gl/gskglrenderer.c | 180 ++++++++++++++++++++++++++++++++++---
gsk/gl/gskglrenderopsprivate.h | 14 +++-
gsk/meson.build | 2 +
gsk/resources/glsl/border.fs.glsl | 32 +++++++
4 files changed, 212 insertions(+), 16 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 782e5b4..063dcbc 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -172,6 +172,7 @@ struct _GskGLRenderer
Program inset_shadow_program;
Program outset_shadow_program;
Program shadow_program;
+ Program border_program;
};
};
@@ -330,6 +331,126 @@ render_text_node (GskGLRenderer *self,
}
}
+static inline void
+render_border_node (GskGLRenderer *self,
+ GskRenderNode *node,
+ RenderOpBuilder *builder)
+{
+ float min_x = node->bounds.origin.x;
+ float min_y = node->bounds.origin.y;
+ float max_x = min_x + node->bounds.size.width;
+ float max_y = min_y + node->bounds.size.height;
+ const GdkRGBA *colors = gsk_border_node_peek_colors (node);
+ const GskRoundedRect *rounded_outline = gsk_border_node_peek_outline (node);
+ const float *widths = gsk_border_node_peek_widths (node);
+ const gboolean needs_clip = TRUE;/*!gsk_rounded_rect_is_rectilinear (rounded_outline);*/
+ GskRoundedRect prev_clip;
+ graphene_rect_t transformed_clip;
+ graphene_rect_t intersection;
+ GskRoundedRect child_clip;
+ RenderOp op;
+ struct {
+ float w;
+ float h;
+ } sizes[4];
+
+ /* Top left */
+ sizes[0].w = MAX (MAX (widths[3], rounded_outline->corner[0].width), 1);
+ sizes[0].h = MAX (MAX (widths[1], rounded_outline->corner[0].height), 1);
+
+ /* Top right */
+ sizes[1].w = MAX (MAX (widths[1], rounded_outline->corner[1].width), 1);
+ sizes[1].h = MAX (MAX (widths[0], rounded_outline->corner[1].height), 1);
+
+ /* Bottom right */
+ sizes[2].w = MAX (MAX (widths[1], rounded_outline->corner[2].width), 1);
+ sizes[2].h = MAX (MAX (widths[2], rounded_outline->corner[2].height), 1);
+
+ /* Bottom left */
+ sizes[3].w = MAX (MAX (widths[3], rounded_outline->corner[3].width), 1);
+ sizes[3].h = MAX (MAX (widths[2], rounded_outline->corner[3].height), 1);
+
+ if (needs_clip)
+ {
+ ops_set_program (builder, &self->border_program);
+
+ transformed_clip = rounded_outline->bounds;
+ graphene_matrix_transform_bounds (&builder->current_modelview, &transformed_clip, &transformed_clip);
+
+ graphene_rect_intersection (&transformed_clip, &builder->current_clip.bounds,
+ &intersection);
+ gsk_rounded_rect_init (&child_clip, &intersection,
+ &rounded_outline->corner[0],
+ &rounded_outline->corner[1],
+ &rounded_outline->corner[2],
+ &rounded_outline->corner[3]);
+
+ prev_clip = ops_set_clip (builder, &child_clip);
+
+ op.op = OP_CHANGE_BORDER;
+ op.border.widths[0] = widths[0];
+ op.border.widths[1] = widths[1];
+ op.border.widths[2] = widths[2];
+ op.border.widths[3] = widths[3];
+ ops_add (builder, &op);
+ }
+ else
+ {
+ ops_set_program (builder, &self->color_program);
+ }
+
+ /* Top */
+ ops_set_color (builder, &colors[0]);
+ ops_draw (builder, (const GskQuadVertex[6]) {
+ { { min_x, min_y }, { 0, 1 }, }, /* Upper left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+
+ { { max_x - sizes[1].w, min_y + sizes[1].h }, { 1, 0 }, }, /* Lower right */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 0, 0 }, }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ });
+
+ /* Right */
+ ops_set_color (builder, &colors[1]);
+ ops_draw (builder, (const GskQuadVertex[6]) {
+ { { max_x - sizes[1].w, min_y + sizes[1].h }, { 0, 1 }, }, /* Upper left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+
+ { { max_x, max_y }, { 1, 0 }, }, /* Lower right */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 0, 0 }, }, /* Lower left */
+ { { max_x, min_y }, { 1, 1 }, }, /* Upper right */
+ });
+
+ /* Bottom */
+ ops_set_color (builder, &colors[2]);
+ ops_draw (builder, (const GskQuadVertex[6]) {
+ { { min_x + sizes[3].w, max_y - sizes[3].h }, { 0, 1 }, }, /* Upper left */
+ { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+
+ { { max_x, max_y }, { 1, 0 }, }, /* Lower right */
+ { { min_x , max_y }, { 0, 0 }, }, /* Lower left */
+ { { max_x - sizes[2].w, max_y - sizes[2].h }, { 1, 1 }, }, /* Upper right */
+ });
+
+ /* Left */
+ ops_set_color (builder, &colors[3]);
+ ops_draw (builder, (const GskQuadVertex[6]) {
+ { { min_x, min_y }, { 0, 1 }, }, /* Upper left */
+ { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+
+ { { min_x + sizes[3].w, max_y - sizes[2].h }, { 1, 0 }, }, /* Lower right */
+ { { min_x, max_y }, { 0, 0 }, }, /* Lower left */
+ { { min_x + sizes[0].w, min_y + sizes[0].h }, { 1, 1 }, }, /* Upper right */
+ });
+
+ if (needs_clip)
+ ops_set_clip (builder, &prev_clip);
+}
+
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
@@ -400,16 +521,17 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
const char *vs;
const char *fs;
} program_definitions[] = {
- { "blend", "blend.vs.glsl", "blend.fs.glsl" },
- { "blit", "blit.vs.glsl", "blit.fs.glsl" },
- { "color", "blit.vs.glsl", "color.fs.glsl" },
- { "coloring", "blit.vs.glsl", "coloring.fs.glsl" },
- { "color matrix", "blit.vs.glsl", "color_matrix.fs.glsl" },
- { "linear gradient", "blit.vs.glsl", "linear_gradient.fs.glsl" },
- { "blur", "blit.vs.glsl", "blur.fs.glsl" },
- { "inset shadow", "blit.vs.glsl", "inset_shadow.fs.glsl" },
- { "outset shadow", "blit.vs.glsl", "outset_shadow.fs.glsl" },
- { "shadow", "blit.vs.glsl", "shadow.fs.glsl" },
+ { "blend", "blend.vs.glsl", "blend.fs.glsl" },
+ { "blit", "blit.vs.glsl", "blit.fs.glsl" },
+ { "color", "blit.vs.glsl", "color.fs.glsl" },
+ { "coloring", "blit.vs.glsl", "coloring.fs.glsl" },
+ { "color matrix", "blit.vs.glsl", "color_matrix.fs.glsl" },
+ { "linear gradient", "blit.vs.glsl", "linear_gradient.fs.glsl" },
+ { "blur", "blit.vs.glsl", "blur.fs.glsl" },
+ { "inset shadow", "blit.vs.glsl", "inset_shadow.fs.glsl" },
+ { "outset shadow", "blit.vs.glsl", "outset_shadow.fs.glsl" },
+ { "shadow", "blit.vs.glsl", "shadow.fs.glsl" },
+ { "border", "blit.vs.glsl", "border.fs.glsl" },
};
builder = gsk_shader_builder_new ();
@@ -523,6 +645,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
/* shadow */
INIT_PROGRAM_UNIFORM_LOCATION2 (shadow, color);
+ /* border */
+ INIT_PROGRAM_UNIFORM_LOCATION2 (border, color);
+ INIT_PROGRAM_UNIFORM_LOCATION2 (border, widths);
+
g_object_unref (builder);
return TRUE;
}
@@ -1122,7 +1248,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
guint i;
/* TODO: shadow nodes are most commonly used for text and icon shadows.
- * In both cases, we can avoit the RTT case!
+ * In both cases, we can avoid the RTT case!
* if the child is neither a text node nor a texture node though, we need
* to fall back to rendering it to a texture and then applying the shadow on that one.*/
@@ -1190,8 +1316,31 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
}
break;
- case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_BORDER_NODE:
+ {
+ /* TODO: The cairo backend is exactly as broken as the code in the following
+ function. test case:
+
+ .foo {
+ border-left: 50px solid #0f0;
+ border-top: 10px solid red;
+ border-bottom: 50px solid teal;
+ border-right: 100px solid pink;
+
+
+ border-radius: 100px;
+ min-height:100px;
+
+ float:left;
+ }
+
+ Or, like, just circular things.
+ */
+ render_border_node (self, node, builder);
+ }
+ break;
+
+ case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_BLEND_NODE:
case GSK_REPEAT_NODE:
@@ -1395,7 +1544,7 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
case OP_CHANGE_COLOR:
OP_PRINT (" -> Color: (%f, %f, %f, %f)", op->color.red, op->color.green, op->color.blue,
op->color.alpha);
g_assert (program == &self->color_program || program == &self->coloring_program ||
- program == &self->shadow_program);
+ program == &self->shadow_program || program == &self->border_program);
/* TODO: We use color.color_location here and this is right for all three of the programs above,
* but that's just a coincidence. */
glUniform4f (program->color.color_location,
@@ -1472,6 +1621,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
glUniform4fv (program->outset_shadow.corner_heights_location, 1, op->outset_shadow.corner_heights);
break;
+ case OP_CHANGE_BORDER:
+ g_assert (program == &self->border_program);
+ glUniform4fv (program->border.widths_location, 1, op->border.widths);
+ break;
+
case OP_DRAW:
OP_PRINT (" -> draw %ld, size %ld and program %s\n",
op->draw.vao_offset, op->draw.vao_size, program->name);
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index ae0ebcf..dfa7bac 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -10,7 +10,7 @@
#include "gskglrendererprivate.h"
#define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 10
+#define GL_N_PROGRAMS 11
enum {
OP_NONE,
@@ -29,8 +29,9 @@ enum {
OP_CHANGE_BLUR = 13,
OP_CHANGE_INSET_SHADOW = 14,
OP_CHANGE_OUTSET_SHADOW = 15,
- OP_CLEAR = 16,
- OP_DRAW = 17,
+ OP_CHANGE_BORDER = 16,
+ OP_CLEAR = 17,
+ OP_DRAW = 18,
};
typedef struct
@@ -93,6 +94,10 @@ typedef struct
int corner_widths_location;
int corner_heights_location;
} outset_shadow;
+ struct {
+ int color_location;
+ int widths_location;
+ } border;
};
} Program;
@@ -152,6 +157,9 @@ typedef struct
struct {
float color[4];
} shadow;
+ struct {
+ float widths[4];
+ } border;
};
} RenderOp;
diff --git a/gsk/meson.build b/gsk/meson.build
index 54828e7..47ac6a4 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -12,6 +12,8 @@ gsk_private_source_shaders = [
'resources/glsl/inset_shadow.fs.glsl',
'resources/glsl/outset_shadow.fs.glsl',
'resources/glsl/shadow.fs.glsl',
+ 'resources/glsl/border.vs.glsl',
+ 'resources/glsl/border.fs.glsl',
'resources/glsl/es2_common.fs.glsl',
'resources/glsl/es2_common.vs.glsl',
'resources/glsl/gl3_common.fs.glsl',
diff --git a/gsk/resources/glsl/border.fs.glsl b/gsk/resources/glsl/border.fs.glsl
new file mode 100644
index 0000000..f605de2
--- /dev/null
+++ b/gsk/resources/glsl/border.fs.glsl
@@ -0,0 +1,32 @@
+uniform vec4 u_color = vec4(1, 0, 1, 1);
+uniform vec4 u_widths;
+
+// For border we abuse, ehm, re-use, the global clip
+// as rounded rect and shrink it by u_widths
+void main() {
+ vec4 bounds = u_clip;
+ vec4 f = gl_FragCoord;
+
+
+ f.x += u_viewport.x;
+ f.y = (u_viewport.y + u_viewport.w) - f.y;
+
+ bounds.z = bounds.x + bounds.z;
+ bounds.w = bounds.y + bounds.w;
+
+ vec4 corner_widths = max (u_clip_corner_widths, u_widths.wyyw);
+ vec4 corner_heights = max (u_clip_corner_heights, u_widths.xxzz);
+
+ RoundedRect routside = RoundedRect (bounds, corner_widths, corner_heights);
+ RoundedRect rinside = rounded_rect_shrink (routside, u_widths);
+
+ float alpha = clamp (rounded_rect_coverage (routside, f.xy) -
+ rounded_rect_coverage (rinside, f.xy),
+ 0.0, 1.0);
+
+ /* Pre-multiply */
+ vec4 color = u_color;
+ color.rgb *= color.a;
+
+ setOutputColor (color * alpha * u_alpha);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]