[gtk/mask-nodes: 3/5] wip: Render fill nodes using a mask shader
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/mask-nodes: 3/5] wip: Render fill nodes using a mask shader
- Date: Tue, 15 Dec 2020 03:24:37 +0000 (UTC)
commit 310dccf03b98b5640e41df64174852c10fe1d21a
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Dec 14 20:35:39 2020 -0500
wip: Render fill nodes using a mask shader
This is not quite finished yet.
gsk/gl/gskglrenderer.c | 56 ++++++++++++++++++++++++++++++++++++-
gsk/gskrendernode.h | 2 ++
gsk/gskrendernodeimpl.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 130 insertions(+), 1 deletion(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 0b8836817b..422d2e9c6d 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -2732,6 +2732,57 @@ render_mask_node (GskGLRenderer *self,
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
}
+static inline void
+render_fill_node (GskGLRenderer *self,
+ GskRenderNode *node,
+ RenderOpBuilder *builder)
+{
+ GskRenderNode *child = gsk_fill_node_get_child (node);
+ GskRenderNode *mask_node;
+ TextureRegion child_region;
+ TextureRegion mask_region;
+ gboolean is_offscreen1, is_offscreen2;
+ OpMask *op;
+
+ if (!add_offscreen_ops (self, builder,
+ &node->bounds,
+ child,
+ &child_region, &is_offscreen1,
+ FORCE_OFFSCREEN | RESET_CLIP))
+ {
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ return;
+ }
+
+ /* FIXME: Figure out how to make the texture coordinates set
+ * up properly without a temporary node
+ */
+ mask_node = gsk_texture_node_new (gsk_fill_node_get_mask (node),
+ &node->bounds);
+
+ if (!add_offscreen_ops (self, builder,
+ &node->bounds,
+ mask_node,
+ &mask_region, &is_offscreen2,
+ FORCE_OFFSCREEN | RESET_CLIP))
+ {
+ gsk_render_node_unref (mask_node);
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ return;
+ }
+
+ gsk_render_node_unref (mask_node);
+
+ ops_set_program (builder, &self->programs->mask_program);
+
+ op = ops_begin (builder, OP_CHANGE_MASK);
+ op->mask = mask_region.texture_id;
+
+ ops_set_texture (builder, child_region.texture_id);
+
+ load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
+}
+
static inline void
render_blend_node (GskGLRenderer *self,
GskRenderNode *node,
@@ -3840,9 +3891,12 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
render_mask_node (self, node, builder);
break;
+ case GSK_FILL_NODE:
+ render_fill_node (self, node, builder);
+ break;
+
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
- case GSK_FILL_NODE:
case GSK_STROKE_NODE:
case GSK_CAIRO_NODE:
default:
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 0e0e893e12..dd0e2ce1ee 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -461,6 +461,8 @@ GDK_AVAILABLE_IN_ALL
GskPath * gsk_fill_node_get_path (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskFillRule gsk_fill_node_get_fill_rule (GskRenderNode *node);
+GDK_AVAILABLE_IN_ALL
+GdkTexture * gsk_fill_node_get_mask (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_stroke_node_get_type (void) G_GNUC_CONST;
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 92b5a85ed1..99914e92e9 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -3670,6 +3670,7 @@ struct _GskFillNode
GskRenderNode *child;
GskPath *path;
GskFillRule fill_rule;
+ GdkTexture *mask;
};
static void
@@ -3680,6 +3681,7 @@ gsk_fill_node_finalize (GskRenderNode *node)
gsk_render_node_unref (self->child);
gsk_path_unref (self->path);
+ g_clear_object (&self->mask);
parent_class->finalize (node);
}
@@ -3740,6 +3742,65 @@ gsk_fill_node_diff (GskRenderNode *node1,
}
}
+static GdkTexture *
+make_path_mask (GskRenderNode *node)
+{
+ GskFillNode *self = (GskFillNode *) node;
+ graphene_rect_t bounds;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ int width;
+ int height;
+ int stride;
+ guchar *buffer;
+ GBytes *bytes;
+ GdkTexture *mask;
+
+ gsk_render_node_get_bounds (node, &bounds);
+ width = ceilf (bounds.size.width);
+ height = ceilf (bounds.size.height);
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
+
+ buffer = g_malloc0 (stride * height);
+ surface = cairo_image_surface_create_for_data (buffer,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ stride);
+
+ cr = cairo_create (surface);
+
+ switch (self->fill_rule)
+ {
+ case GSK_FILL_RULE_WINDING:
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+ break;
+ case GSK_FILL_RULE_EVEN_ODD:
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ gsk_path_to_cairo (self->path, cr);
+ cairo_clip (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+
+ bytes = g_bytes_new_take (buffer, stride * height);
+ mask = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride);
+ g_bytes_unref (bytes);
+
+ gdk_texture_save_to_png (mask, "mask.png");
+
+ cairo_surface_destroy (surface);
+
+ return mask;
+}
+
/**
* gsk_fill_node_new:
* @child: The node to fill the area with
@@ -3775,6 +3836,8 @@ gsk_fill_node_new (GskRenderNode *child,
else
graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ());
+ self->mask = make_path_mask (node);
+
return node;
}
@@ -3833,6 +3896,16 @@ gsk_fill_node_get_fill_rule (GskRenderNode *node)
return self->fill_rule;
}
+GdkTexture *
+gsk_fill_node_get_mask (GskRenderNode *node)
+{
+ GskFillNode *self = (GskFillNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL);
+
+ return self->mask;
+}
+
/*** GSK_STROKE_NODE ***/
struct _GskStrokeNode
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]