[mutter/gbsneto/effects-paint-nodes: 22/22] Introduce ClutterBlitNode
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/gbsneto/effects-paint-nodes: 22/22] Introduce ClutterBlitNode
- Date: Wed, 8 Jul 2020 16:57:23 +0000 (UTC)
commit 027f9d6b3d30444353711ebca867d9bf03ba57fa
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Mon Jun 29 15:26:58 2020 -0300
Introduce ClutterBlitNode
It is not possible to express a blit operation using paint
nodes as of now. This is a requirement for GNOME Shell, e.g.,
to implement its blur effect.
Add a new ClutterBlitNode node that takes two framebuffers as
input, and blits source into dest according to added rectangles.
Because this paint node uses the rectangles in a different way
compared to all the other nodes, add an auxiliary method to
ensure all blit operations are valid.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
clutter/clutter/clutter-paint-nodes.c | 203 ++++++++++++++++++++++++++++++++++
clutter/clutter/clutter-paint-nodes.h | 32 ++++++
2 files changed, 235 insertions(+)
---
diff --git a/clutter/clutter/clutter-paint-nodes.c b/clutter/clutter/clutter-paint-nodes.c
index 3b20792e47..90851cf4ed 100644
--- a/clutter/clutter/clutter-paint-nodes.c
+++ b/clutter/clutter/clutter-paint-nodes.c
@@ -1625,3 +1625,206 @@ clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
return (ClutterPaintNode *) res;
}
+
+/*
+ * ClutterBlitNode
+ */
+
+struct _ClutterBlitNode
+{
+ ClutterPaintNode parent_instance;
+
+ CoglFramebuffer *source;
+ CoglFramebuffer *dest;
+};
+
+struct _ClutterBlitNodeClass
+{
+ ClutterPaintNodeClass parent_class;
+};
+
+G_DEFINE_TYPE (ClutterBlitNode, clutter_blit_node, CLUTTER_TYPE_PAINT_NODE)
+
+static gboolean
+clutter_blit_node_pre_draw (ClutterPaintNode *node,
+ ClutterPaintContext *paint_context)
+{
+ return TRUE;
+}
+
+static void
+clutter_blit_node_draw (ClutterPaintNode *node,
+ ClutterPaintContext *paint_context)
+{
+ ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
+ g_autoptr (GError) error = NULL;
+ CoglFramebuffer *source;
+ guint i;
+
+ if (node->operations == NULL)
+ return;
+
+ source = blit_node->source;
+ if (!source)
+ source = clutter_paint_context_get_framebuffer (paint_context);
+
+ for (i = 0; i < node->operations->len; i++)
+ {
+ const ClutterPaintOperation *op;
+ float op_width, op_height;
+
+ op = &g_array_index (node->operations, ClutterPaintOperation, i);
+
+ switch (op->opcode)
+ {
+ case PAINT_OP_INVALID:
+ break;
+
+ case PAINT_OP_TEX_RECT:
+ op_width = op->op.texrect[6] - op->op.texrect[4];
+ op_height = op->op.texrect[7] - op->op.texrect[5];
+
+ cogl_blit_framebuffer (source,
+ blit_node->dest,
+ op->op.texrect[0],
+ op->op.texrect[1],
+ op->op.texrect[4],
+ op->op.texrect[5],
+ op_width,
+ op_height,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Error blitting framebuffers: %s", error->message);
+ return;
+ }
+ break;
+
+ case PAINT_OP_MULTITEX_RECT:
+ case PAINT_OP_PRIMITIVE:
+ break;
+ }
+ }
+}
+
+static void
+clutter_blit_node_finalize (ClutterPaintNode *node)
+{
+ ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
+
+ cogl_clear_object (&blit_node->source);
+ cogl_clear_object (&blit_node->dest);
+
+ CLUTTER_PAINT_NODE_CLASS (clutter_blit_node_parent_class)->finalize (node);
+}
+
+static JsonNode *
+clutter_blit_node_serialize (ClutterPaintNode *node)
+{
+ ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
+ g_autoptr (JsonBuilder) builder = NULL;
+ g_autofree char *source_ptr = NULL;
+ g_autofree char *dest_ptr = NULL;
+
+ builder = json_builder_new ();
+
+ source_ptr = g_strdup_printf ("%p", blit_node->source);
+ dest_ptr = g_strdup_printf ("%p", blit_node->dest);
+
+ json_builder_begin_object (builder);
+ json_builder_set_member_name (builder, "source");
+ json_builder_add_string_value (builder, source_ptr);
+ json_builder_end_object (builder);
+
+ json_builder_begin_object (builder);
+ json_builder_set_member_name (builder, "dest");
+ json_builder_add_string_value (builder, dest_ptr);
+ json_builder_end_object (builder);
+
+ return json_builder_get_root (builder);
+}
+
+static void
+clutter_blit_node_class_init (ClutterTransformNodeClass *klass)
+{
+ ClutterPaintNodeClass *node_class;
+
+ node_class = CLUTTER_PAINT_NODE_CLASS (klass);
+ node_class->pre_draw = clutter_blit_node_pre_draw;
+ node_class->draw = clutter_blit_node_draw;
+ node_class->finalize = clutter_blit_node_finalize;
+ node_class->serialize = clutter_blit_node_serialize;
+}
+
+static void
+clutter_blit_node_init (ClutterBlitNode *self)
+{
+}
+
+/**
+ * clutter_blit_node_new:
+ * @source: (nullable): the source #CoglFramebuffer
+ * @dest: the destination #CoglFramebuffer
+ *
+ * Creates a new #ClutterBlitNode that blits @source into @dest.
+ *
+ * If @source is %NULL, the most recent framebuffer stacked into a
+ * #ClutterPaintContext is used.
+ *
+ * You must only add rectangles using clutter_blit_node_add_blit_rectangle().
+ *
+ * Return value: (transfer full): the newly created #ClutterBlitNode.
+ * Use clutter_paint_node_unref() when done.
+ */
+ClutterPaintNode *
+clutter_blit_node_new (CoglFramebuffer *source,
+ CoglFramebuffer *dest)
+{
+ ClutterBlitNode *res;
+
+ g_return_val_if_fail (cogl_is_framebuffer (dest), NULL);
+
+ res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
+ res->source = source ? cogl_object_ref (source) : NULL;
+ res->dest = cogl_object_ref (dest);
+
+ return (ClutterPaintNode *) res;
+}
+
+/**
+ * clutter_blit_node_add_blit_rectangle:
+ * @blit_node: a #ClutterBlitNode
+ * @src_x: Source x position
+ * @src_y: Source y position
+ * @dst_x: Destination x position
+ * @dst_y: Destination y position
+ * @width: Width of region to copy
+ * @height: Height of region to copy
+ *
+ * Adds a new blit rectangle to the stack of rectangles. All the
+ * constraints of cogl_blit_framebuffer() apply here.
+ */
+void
+clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ int width,
+ int height)
+{
+ g_return_if_fail (CLUTTER_IS_BLIT_NODE (blit_node));
+
+ clutter_paint_node_add_texture_rectangle (CLUTTER_PAINT_NODE (blit_node),
+ &(ClutterActorBox) {
+ src_x,
+ src_y,
+ src_x + width,
+ src_y + height,
+ },
+ dst_x,
+ dst_y,
+ dst_x + width,
+ dst_y + height);
+}
diff --git a/clutter/clutter/clutter-paint-nodes.h b/clutter/clutter/clutter-paint-nodes.h
index 5303718ba7..0a0ee743f3 100644
--- a/clutter/clutter/clutter-paint-nodes.h
+++ b/clutter/clutter/clutter-paint-nodes.h
@@ -236,6 +236,38 @@ GType clutter_transform_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
+#define CLUTTER_TYPE_BLIT_NODE (clutter_blit_node_get_type ())
+#define CLUTTER_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLIT_NODE,
ClutterBlitNode))
+#define CLUTTER_IS_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLIT_NODE))
+
+/*
+ * ClutterBlitNode:
+ *
+ * The #ClutterLayerNode structure is an opaque
+ * type whose members cannot be directly accessed.
+ *
+ * Since: 1.10
+ */
+typedef struct _ClutterBlitNode ClutterBlitNode;
+typedef struct _ClutterPaintNodeClass ClutterBlitNodeClass;
+
+CLUTTER_EXPORT
+GType clutter_blit_node_get_type (void) G_GNUC_CONST;
+
+CLUTTER_EXPORT
+ClutterPaintNode * clutter_blit_node_new (CoglFramebuffer *source,
+ CoglFramebuffer *dest);
+
+
+CLUTTER_EXPORT
+void clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ int width,
+ int height);
+
G_END_DECLS
#endif /* __CLUTTER_PAINT_NODES_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]