[mutter/gbsneto/effects-paint-nodes: 88/88] Introduce ClutterBlitNode



commit cfd73cfe825538c773a822749eaa5cb64215e70e
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 f8f35e45c3..322dedd0d6 100644
--- a/clutter/clutter/clutter-paint-nodes.c
+++ b/clutter/clutter/clutter-paint-nodes.c
@@ -1606,3 +1606,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_layer_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 75015aef6e..61f4674e69 100644
--- a/clutter/clutter/clutter-paint-nodes.h
+++ b/clutter/clutter/clutter-paint-nodes.h
@@ -235,6 +235,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]