[gtk+/wip/otte/rendernode: 31/100] gsk: gsk_render_node_set_transform() => GskTransformNode



commit ddbde723e642c828404fbb0b1c21324877ffef19
Author: Benjamin Otte <otte redhat com>
Date:   Tue Dec 13 00:11:06 2016 +0100

    gsk: gsk_render_node_set_transform() => GskTransformNode
    
    Instead of having a setter for the transform, have a GskTransformNode.
    
    Most of the oprations that GTK does do not require a transform, so it
    doesn't make sense to have it as a primary attribute.
    
    Also, changing the transform requires updating the uniforms of the GL
    renderer, so we're happy if we can avoid that.

 docs/reference/gsk/gsk4-sections.txt   |    3 +-
 gsk/gskcairorenderer.c                 |   35 +++++---
 gsk/gskenums.h                         |    5 +-
 gsk/gskglrenderer.c                    |   25 ++++--
 gsk/gskrendernode.c                    |   43 ----------
 gsk/gskrendernode.h                    |    5 +-
 gsk/gskrendernodeimpl.c                |  109 +++++++++++++++++++++++++
 gsk/gskrendernodeprivate.h             |    7 +-
 gsk/gskvulkanrender.c                  |    4 +-
 gsk/gskvulkanrenderpass.c              |  111 ++++++++++++++++++--------
 gsk/gskvulkanrenderpassprivate.h       |    4 +-
 gtk/gtkrendericon.c                    |   99 ++++++++++++++++-------
 gtk/gtksnapshot.c                      |  138 ++++++++++---------------------
 gtk/gtksnapshot.h                      |   10 +--
 gtk/gtksnapshotprivate.h               |   11 +--
 gtk/inspector/gtktreemodelrendernode.c |    4 +
 gtk/inspector/recorder.c               |   23 -----
 17 files changed, 366 insertions(+), 270 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 1fe5cdd..102d084 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -28,7 +28,6 @@ gsk_render_node_ref
 gsk_render_node_unref
 GskRenderNodeType
 gsk_render_node_get_node_type
-gsk_render_node_set_transform
 gsk_render_node_set_opacity
 GskBlendMode
 gsk_render_node_set_blend_mode
@@ -42,6 +41,8 @@ gsk_container_node_new
 gsk_container_node_append_child
 gsk_container_node_get_n_children
 gsk_container_node_get_child
+gsk_transform_node_new
+gsk_transform_node_get_child
 <SUBSECTION Standard>
 GSK_IS_RENDER_NODE
 GSK_RENDER_NODE
diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c
index 7d4dcff..4fd8592 100644
--- a/gsk/gskcairorenderer.c
+++ b/gsk/gskcairorenderer.c
@@ -52,24 +52,10 @@ gsk_cairo_renderer_render_node (GskCairoRenderer *self,
                                 cairo_t          *cr)
 {
   gboolean pop_group = FALSE;
-  graphene_matrix_t mat;
-  cairo_matrix_t ctm;
   graphene_rect_t frame;
 
   cairo_save (cr);
 
-  gsk_render_node_get_transform (node, &mat);
-  if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
-    {
-      GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
-                                ctm.xx, ctm.yx,
-                                ctm.xy, ctm.yy,
-                                ctm.x0, ctm.y0));
-      cairo_transform (cr, &ctm);
-    }
-  else
-    g_critical ("Invalid non-affine transformation for node %p", node);
-
   gsk_render_node_get_bounds (node, &frame);
   GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
                             frame.origin.x, frame.origin.y,
@@ -131,6 +117,27 @@ gsk_cairo_renderer_render_node (GskCairoRenderer *self,
         cairo_paint (cr);
       }
       break;
+
+    case GSK_TRANSFORM_NODE:
+      {
+        graphene_matrix_t mat;
+        cairo_matrix_t ctm;
+
+        gsk_transform_node_get_transform (node, &mat);
+        if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
+          {
+            GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g 
}\n",
+                                      ctm.xx, ctm.yx,
+                                      ctm.xy, ctm.yy,
+                                      ctm.x0, ctm.y0));
+            cairo_transform (cr, &ctm);
+          }
+        else
+          g_critical ("Invalid non-affine transformation for node %p", node);
+
+        gsk_cairo_renderer_render_node (self, gsk_transform_node_get_child (node), cr);
+      }
+      break;
     }
 
   if (GSK_RENDER_MODE_CHECK (GEOMETRY))
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 9040c69..26ce47f 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -28,6 +28,8 @@
  * @GSK_CONTAINER_NODE: A node containing a stack of children
  * @GSK_CAIRO_NODE: A node drawing a #cairo_surface_t
  * @GSK_TEXTURE_NODE: A node drawing a #GskTexture
+ * @GSK_TRANSFORM_NODE: A node that renders its child after applying a
+ *     matrix transform
  *
  * The type of a node determines what the node is rendering.
  *
@@ -37,7 +39,8 @@ typedef enum {
   GSK_NOT_A_RENDER_NODE = 0,
   GSK_CONTAINER_NODE,
   GSK_CAIRO_NODE,
-  GSK_TEXTURE_NODE
+  GSK_TEXTURE_NODE,
+  GSK_TRANSFORM_NODE
 } GskRenderNodeType;
 
 /**
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 36b158f..5cbb0a0 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -603,13 +603,12 @@ render_node_needs_render_target (GskRenderNode *node)
 static void
 gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
                                  const graphene_matrix_t *projection,
-                                 const graphene_matrix_t *parent_modelview,
+                                 const graphene_matrix_t *modelview,
                                  GArray                  *render_items,
                                  GskRenderNode           *node,
                                  RenderItem              *parent)
 {
   graphene_rect_t viewport;
-  graphene_matrix_t mv, transform;
   graphene_rect_t bounds;
   RenderItem item;
   RenderItem *ritem = NULL;
@@ -645,10 +644,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
   item.max.z = 0.f;
 
   /* The location of the item, in normalized world coordinates */
-  gsk_render_node_get_transform (node, &transform);
-  graphene_matrix_multiply (&transform, parent_modelview, &mv);
-  graphene_matrix_multiply (&mv, &self->mvp, &item.mvp);
-  item.z = project_item (projection, &mv);
+  graphene_matrix_multiply (modelview, &self->mvp, &item.mvp);
+  item.z = project_item (projection, modelview);
 
   item.opacity = gsk_render_node_get_opacity (node);
 
@@ -743,11 +740,25 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
         for (i = 0; i < gsk_container_node_get_n_children (node); i++)
           {
             GskRenderNode *child = gsk_container_node_get_child (node, i);
-            gsk_gl_renderer_add_render_item (self, projection, &mv, render_items, child, ritem);
+            gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem);
           }
       }
       return;
 
+    case GSK_TRANSFORM_NODE:
+      {
+        graphene_matrix_t transform, transformed_mv;
+
+        gsk_transform_node_get_transform (node, &transform);
+        graphene_matrix_multiply (&transform, modelview, &transformed_mv);
+        gsk_gl_renderer_add_render_item (self,
+                                         projection, &transformed_mv,
+                                         render_items,
+                                         gsk_transform_node_get_child (node),
+                                         ritem);
+      }
+      return;
+
     case GSK_NOT_A_RENDER_NODE:
     default:
       return;
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index 641ab2f..5b53c91 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -97,8 +97,6 @@ gsk_render_node_new (const GskRenderNodeClass *node_class)
 
   self->ref_count = 1;
 
-  graphene_matrix_init_identity (&self->transform);
-
   self->opacity = 1.0;
 
   self->min_filter = GSK_SCALING_FILTER_NEAREST;
@@ -188,47 +186,6 @@ gsk_render_node_get_bounds (GskRenderNode   *node,
 }
 
 /**
- * gsk_render_node_set_transform:
- * @node: a #GskRenderNode
- * @transform: (nullable): a transformation matrix
- *
- * Sets the transformation matrix used when rendering the @node.
- *
- * Since: 3.90
- */
-void
-gsk_render_node_set_transform (GskRenderNode           *node,
-                               const graphene_matrix_t *transform)
-{
-  g_return_if_fail (GSK_IS_RENDER_NODE (node));
-  g_return_if_fail (node->is_mutable);
-
-  if (transform == NULL)
-    graphene_matrix_init_identity (&node->transform);
-  else
-    graphene_matrix_init_from_matrix (&node->transform, transform);
-}
-
-/**
- * gsk_render_node_get_transform:
- * @node: a #GskRenderNode
- * @mv: (out caller-allocates): return location for the transform matrix
- *
- * Retrieves the transform matrix set using gsk_render_node_set_transform().
- *
- * Since: 3.90
- */
-void
-gsk_render_node_get_transform (GskRenderNode     *node,
-                               graphene_matrix_t *mv)
-{
-  g_return_if_fail (GSK_IS_RENDER_NODE (node));
-  g_return_if_fail (mv != NULL);
-
-  graphene_matrix_init_from_matrix (mv, &node->transform);
-}
-
-/**
  * gsk_render_node_set_opacity:
  * @node: a #GskRenderNode
  * @opacity: the opacity of the node, between 0 (fully transparent) and
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 70d26a5..b98bd56 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -66,9 +66,12 @@ GskRenderNode *         gsk_container_node_get_child            (GskRenderNode
                                                                  guint                    idx);
 
 GDK_AVAILABLE_IN_3_90
-void                    gsk_render_node_set_transform           (GskRenderNode            *node,
+GskRenderNode *         gsk_transform_node_new                  (GskRenderNode            *child,
                                                                  const graphene_matrix_t  *transform);
 GDK_AVAILABLE_IN_3_90
+GskRenderNode *         gsk_transform_node_get_child            (GskRenderNode            *node);
+
+GDK_AVAILABLE_IN_3_90
 void                    gsk_render_node_set_opacity             (GskRenderNode *node,
                                                                  double         opacity);
 
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 40c2ad6..e719a1d 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -424,3 +424,112 @@ gsk_container_node_get_child (GskRenderNode *node,
   return g_ptr_array_index (container->children, idx);
 }
 
+/*** GSK_TRANSFORM_NODE ***/
+
+typedef struct _GskTransformNode GskTransformNode;
+
+struct _GskTransformNode
+{
+  GskRenderNode render_node;
+
+  GskRenderNode *child;
+  graphene_matrix_t transform;
+};
+
+static void
+gsk_transform_node_finalize (GskRenderNode *node)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+
+  gsk_render_node_unref (self->child);
+}
+
+static void
+gsk_transform_node_make_immutable (GskRenderNode *node)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+
+  gsk_render_node_make_immutable (self->child);
+}
+
+static void
+gsk_transform_node_get_bounds (GskRenderNode   *node,
+                           graphene_rect_t *bounds)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+  graphene_rect_t child_bounds;
+
+  gsk_render_node_get_bounds (self->child, &child_bounds);
+
+  graphene_matrix_transform_bounds (&self->transform,
+                                    &child_bounds,
+                                    bounds);
+}
+
+static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
+  GSK_TRANSFORM_NODE,
+  sizeof (GskTransformNode),
+  "GskTransformNode",
+  gsk_transform_node_finalize,
+  gsk_transform_node_make_immutable,
+  gsk_transform_node_get_bounds
+};
+
+/**
+ * gsk_transform_node_new:
+ * @child: The node to transform
+ * @transform: The transform to apply
+ *
+ * Creates a #GskRenderNode that will transform the given @child
+ * with the given @transform.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_transform_node_new (GskRenderNode           *child,
+                        const graphene_matrix_t *transform)
+{
+  GskTransformNode *self;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+  g_return_val_if_fail (transform != NULL, NULL);
+
+  self = (GskTransformNode *) gsk_render_node_new (&GSK_TRANSFORM_NODE_CLASS);
+
+  self->child = gsk_render_node_ref (child);
+  graphene_matrix_init_from_matrix (&self->transform, transform);
+
+  return &self->render_node;
+}
+
+/**
+ * gsk_transform_node_get_child:
+ * @node: a transform @GskRenderNode
+ *
+ * Gets the child node that is getting transformed by the given @node.
+ *
+ * Returns: (transfer none): The child that is getting transformed
+ **/
+GskRenderNode *
+gsk_transform_node_get_child (GskRenderNode *node)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE), NULL);
+
+  return self->child;
+}
+
+void
+gsk_transform_node_get_transform (GskRenderNode     *node,
+                                  graphene_matrix_t *transform)
+{
+  GskTransformNode *self = (GskTransformNode *) node;
+
+  g_return_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE));
+
+  graphene_matrix_init_from_matrix (transform, &self->transform);
+}
+
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 5e35396..85117f4 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -29,9 +29,6 @@ struct _GskRenderNode
   GskScalingFilter min_filter;
   GskScalingFilter mag_filter;
 
-  /* Transformations applied to the node */
-  graphene_matrix_t transform;
-
   /* Bit fields; leave at the end */
   gboolean is_mutable : 1;
 };
@@ -53,14 +50,14 @@ void gsk_render_node_make_immutable (GskRenderNode *node);
 
 void gsk_render_node_get_bounds (GskRenderNode   *node,
                                  graphene_rect_t *frame);
-void gsk_render_node_get_transform (GskRenderNode     *node,
-                                    graphene_matrix_t *mv);
 double gsk_render_node_get_opacity (GskRenderNode *node);
 
 cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
 
 GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);
 
+void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform);
+
 GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);
 
 G_END_DECLS
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index 8c14519..8727cde 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -233,7 +233,7 @@ gsk_vulkan_render_add_node (GskVulkanRender *self,
 
   self->render_passes = g_slist_prepend (self->render_passes, pass);
 
-  gsk_vulkan_render_pass_add_node (pass, self, node);
+  gsk_vulkan_render_pass_add (pass, self, &self->mvp, node);
 }
 
 void
@@ -466,7 +466,7 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
 
   for (l = self->render_passes; l; l = l->next)
     {
-      gsk_vulkan_render_pass_draw (l->data, self, &self->mvp, self->pipeline, self->command_buffer);
+      gsk_vulkan_render_pass_draw (l->data, self, self->pipeline, self->command_buffer);
     }
 
   vkCmdEndRenderPass (self->command_buffer);
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index f9398f2..595ad63 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -12,7 +12,8 @@ typedef struct _GskVulkanRenderOp GskVulkanRenderOp;
 typedef enum {
   GSK_VULKAN_OP_FALLBACK,
   GSK_VULKAN_OP_SURFACE,
-  GSK_VULKAN_OP_TEXTURE
+  GSK_VULKAN_OP_TEXTURE,
+  GSK_VULKAN_OP_BIND_MVP
 } GskVulkanOpType;
 
 struct _GskVulkanRenderOp
@@ -20,6 +21,7 @@ struct _GskVulkanRenderOp
   GskVulkanOpType      type;
   GskRenderNode       *node; /* node that's the source of this op */
   GskVulkanImage      *source; /* source image to render */
+  graphene_matrix_t    mvp; /* new mvp to set */
   gsize                vertex_offset; /* offset into vertex buffer */
   gsize                vertex_count; /* number of vertices */
   gsize                descriptor_set_index; /* index into descriptor sets array for the right descriptor 
set to bind */
@@ -54,9 +56,10 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
 }
 
 void
-gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
-                                 GskVulkanRender     *render,
-                                 GskRenderNode       *node)
+gsk_vulkan_render_pass_add_node (GskVulkanRenderPass     *self,
+                                 GskVulkanRender         *render,
+                                 const graphene_matrix_t *mvp,
+                                 GskRenderNode           *node)
 {
   GskVulkanRenderOp op = {
     .type = GSK_VULKAN_OP_FALLBACK,
@@ -89,10 +92,24 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
 
         for (i = 0; i < gsk_container_node_get_n_children (node); i++)
           {
-            gsk_vulkan_render_pass_add_node (self, render, gsk_container_node_get_child (node, i));
+            gsk_vulkan_render_pass_add_node (self, render, mvp, gsk_container_node_get_child (node, i));
           }
       }
       break;
+    case GSK_TRANSFORM_NODE:
+      {
+        graphene_matrix_t transform;
+
+        op.type = GSK_VULKAN_OP_BIND_MVP;
+        gsk_transform_node_get_transform (node, &transform);
+        graphene_matrix_multiply (&transform, mvp, &op.mvp);
+        g_array_append_val (self->render_ops, op);
+        gsk_vulkan_render_pass_add_node (self, render, &op.mvp, gsk_transform_node_get_child (node));
+        graphene_matrix_init_from_matrix (&op.mvp, mvp);
+        g_array_append_val (self->render_ops, op);
+      }
+      break;
+
     }
 
   return;
@@ -101,6 +118,22 @@ fallback:
   g_array_append_val (self->render_ops, op);
 }
 
+void
+gsk_vulkan_render_pass_add (GskVulkanRenderPass     *self,
+                            GskVulkanRender         *render,
+                            const graphene_matrix_t *mvp,
+                            GskRenderNode           *node)
+{
+  GskVulkanRenderOp op = {
+    .type = GSK_VULKAN_OP_BIND_MVP,
+    .mvp = *mvp
+  };
+
+  g_array_append_val (self->render_ops, op);
+
+  gsk_vulkan_render_pass_add_node (self, render, mvp, node);
+}
+
 static void
 gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
                                         GskVulkanRenderOp   *op,
@@ -182,6 +215,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
 
         default:
           g_assert_not_reached ();
+        case GSK_VULKAN_OP_BIND_MVP:
           break;
         }
     }
@@ -237,6 +271,9 @@ gsk_vulkan_render_pass_collect_vertices (GskVulkanRenderPass *self,
 
         default:
           g_assert_not_reached ();
+        case GSK_VULKAN_OP_BIND_MVP:
+          op->vertex_offset = 0;
+          op->vertex_count = 0;
           break;
         }
 
@@ -268,6 +305,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
 
         default:
           g_assert_not_reached ();
+        case GSK_VULKAN_OP_BIND_MVP:
           break;
         }
     }
@@ -276,12 +314,10 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
 void
 gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
                              GskVulkanRender         *render,
-                             const graphene_matrix_t *parent_mvp,
                              GskVulkanPipeline       *pipeline,
                              VkCommandBuffer          command_buffer)
 {
   GskVulkanRenderOp *op;
-  graphene_matrix_t transform, mvp;
   float float_matrix[16];
   guint i;
 
@@ -289,30 +325,41 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
     {
       op = &g_array_index (self->render_ops, GskVulkanRenderOp, i);
 
-      vkCmdBindDescriptorSets (command_buffer,
-                               VK_PIPELINE_BIND_POINT_GRAPHICS,
-                               gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
-                               0,
-                               1,
-                               (VkDescriptorSet[1]) {
-                                   gsk_vulkan_render_get_descriptor_set (render, op->descriptor_set_index)
-                               },
-                               0,
-                               NULL);
-
-      gsk_render_node_get_transform (op->node, &transform);
-      graphene_matrix_multiply (&transform, parent_mvp, &mvp);
-      graphene_matrix_to_float (&mvp, float_matrix);
-
-      vkCmdPushConstants (command_buffer,
-                          gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
-                          VK_SHADER_STAGE_VERTEX_BIT,
-                          0,
-                          sizeof (float_matrix),
-                          &float_matrix);
-
-      vkCmdDraw (command_buffer,
-                 op->vertex_count, 1,
-                 op->vertex_offset, 0);
+      switch (op->type)
+        {
+        case GSK_VULKAN_OP_FALLBACK:
+        case GSK_VULKAN_OP_SURFACE:
+        case GSK_VULKAN_OP_TEXTURE:
+          vkCmdBindDescriptorSets (command_buffer,
+                                   VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                   gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
+                                   0,
+                                   1,
+                                   (VkDescriptorSet[1]) {
+                                       gsk_vulkan_render_get_descriptor_set (render, 
op->descriptor_set_index)
+                                   },
+                                   0,
+                                   NULL);
+
+          vkCmdDraw (command_buffer,
+                     op->vertex_count, 1,
+                     op->vertex_offset, 0);
+          break;
+
+        case GSK_VULKAN_OP_BIND_MVP:
+          graphene_matrix_to_float (&op->mvp, float_matrix);
+          vkCmdPushConstants (command_buffer,
+                              gsk_vulkan_pipeline_get_pipeline_layout (pipeline),
+                              VK_SHADER_STAGE_VERTEX_BIT,
+                              0,
+                              sizeof (float_matrix),
+                              &float_matrix);
+
+          break;
+
+        default:
+          g_assert_not_reached ();
+          break;
+        }
     }
 }
diff --git a/gsk/gskvulkanrenderpassprivate.h b/gsk/gskvulkanrenderpassprivate.h
index 1cc826d..5bb8d01 100644
--- a/gsk/gskvulkanrenderpassprivate.h
+++ b/gsk/gskvulkanrenderpassprivate.h
@@ -13,8 +13,9 @@ typedef struct _GskVulkanRenderPass GskVulkanRenderPass;
 GskVulkanRenderPass *   gsk_vulkan_render_pass_new                      (GdkVulkanContext       *context);
 void                    gsk_vulkan_render_pass_free                     (GskVulkanRenderPass    *self);
 
-void                    gsk_vulkan_render_pass_add_node                 (GskVulkanRenderPass    *self,
+void                    gsk_vulkan_render_pass_add                      (GskVulkanRenderPass    *self,
                                                                          GskVulkanRender        *render,
+                                                                         const graphene_matrix_t*mvp,
                                                                          GskRenderNode          *node);
 
 void                    gsk_vulkan_render_pass_upload                   (GskVulkanRenderPass    *self,
@@ -31,7 +32,6 @@ void                    gsk_vulkan_render_pass_reserve_descriptor_sets  (GskVulk
                                                                          GskVulkanRender        *render);
 void                    gsk_vulkan_render_pass_draw                     (GskVulkanRenderPass    *self,
                                                                          GskVulkanRender        *render,
-                                                                         const graphene_matrix_t*root_mvp,
                                                                          GskVulkanPipeline      *pipeline,
                                                                          VkCommandBuffer         
command_buffer);
 
diff --git a/gtk/gtkrendericon.c b/gtk/gtkrendericon.c
index 409e940..0304f0d 100644
--- a/gtk/gtkrendericon.c
+++ b/gtk/gtkrendericon.c
@@ -96,9 +96,9 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
                              GtkCssImageBuiltinType  builtin_type)
 {
   const GtkCssValue *shadows, *transform;
-  graphene_matrix_t transform_matrix, m1, m2, m3, saved_matrix;
-  GtkCssImage *image;
   static gboolean shadow_warning;
+  graphene_matrix_t transform_matrix;
+  GtkCssImage *image;
 
   g_return_if_fail (GTK_IS_CSS_STYLE (style));
   g_return_if_fail (snapshot != NULL);
@@ -113,23 +113,39 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
   if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
     return;
 
-  graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot));
-
-  /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
-  graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0));
-  graphene_matrix_multiply (&transform_matrix, &m1, &m3);
-  graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
-  graphene_matrix_multiply (&m2, &m3, &m1);
-  gtk_snapshot_transform (snapshot, &m1);
-
   if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
     {
       g_warning ("Painting shadows not implemented for textures yet.");
       shadow_warning = TRUE;
     }
-  gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
 
-  gtk_snapshot_set_transform (snapshot, &saved_matrix);
+  if (graphene_matrix_is_identity (&transform_matrix))
+    {
+      gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
+    }
+  else
+    {
+      graphene_matrix_t m1, m2, m3;
+      GskRenderNode *transform_node, *container_node;
+      double offset_x, offset_y;
+
+      gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+      /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
+      graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + height 
/ 2.0, 0));
+      graphene_matrix_multiply (&transform_matrix, &m1, &m3);
+      graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
+      graphene_matrix_multiply (&m2, &m3, &m1);
+
+      container_node = gsk_container_node_new ();
+      gsk_render_node_set_name (container_node, "CSS Icon Transform Container");
+      transform_node = gsk_transform_node_new (container_node, &m1);
+      gsk_render_node_set_name (transform_node, "CSS Icon Transform");
+      gtk_snapshot_append_node (snapshot, transform_node);
+      
+      gtk_snapshot_push_node (snapshot, container_node);
+      gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
+      gtk_snapshot_pop (snapshot);
+    }
 }
 
 static gboolean
@@ -253,9 +269,9 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
                                      double       texture_scale)
 {
   const GtkCssValue *shadows, *transform;
-  graphene_matrix_t transform_matrix, translate, matrix, saved_matrix;
+  graphene_matrix_t transform_matrix;
   graphene_rect_t bounds;
-  GskRenderNode *node;
+  GskRenderNode *icon_node, *transform_node;
   double width, height;
   static gboolean shadow_warning;
 
@@ -272,26 +288,47 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
   if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
     return;
 
-  graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot));
-
-  /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
-  graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0));
-  graphene_matrix_multiply (&transform_matrix, &translate, &matrix);
-  graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
-  graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1);
-  gtk_snapshot_transform (snapshot, &matrix);
-
-  graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
-
-  node = gsk_texture_node_new (texture, &bounds);
-  gsk_render_node_set_name (node, "Icon");
-  gtk_snapshot_append_node (snapshot, node);
   if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
     {
       g_warning ("Painting shadows not implemented for textures yet.");
       shadow_warning = TRUE;
     }
-  gsk_render_node_unref (node);
 
-  gtk_snapshot_set_transform (snapshot, &saved_matrix);
+  if (graphene_matrix_is_identity (&transform_matrix))
+    {
+      double offset_x, offset_y;
+
+      gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+      graphene_rect_init (&bounds,
+                          offset_x, offset_y,
+                          gsk_texture_get_width (texture) / texture_scale,
+                          gsk_texture_get_height (texture) / texture_scale);
+      icon_node = gsk_texture_node_new (texture, &bounds);
+      gsk_render_node_set_name (icon_node, "Icon");
+      
+      gtk_snapshot_append_node (snapshot, icon_node);
+    }
+  else
+    {
+      graphene_matrix_t translate, matrix;
+      double offset_x, offset_y;
+
+      gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
+      /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
+      graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + 
height / 2.0, 0));
+      graphene_matrix_multiply (&transform_matrix, &translate, &matrix);
+      graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
+      graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1);
+
+      graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
+      icon_node = gsk_texture_node_new (texture, &bounds);
+      gsk_render_node_set_name (icon_node, "Icon");
+
+      transform_node = gsk_transform_node_new (icon_node, &matrix);
+      gsk_render_node_set_name (transform_node, "Icon Transform");
+      gtk_snapshot_append_node (snapshot, transform_node);
+
+      gsk_render_node_unref (icon_node);
+      gsk_render_node_unref (transform_node);
+    }
 }
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 63d5a6a..946c308 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -41,7 +41,7 @@
  * transformations.
  *
  * The node at the top of the stack is the the one that gtk_snapshot_append_node()
- * operates on. Use the gtk_snapshot_push_() and gtk_snapshot_pop() functions to
+ * operates on. Use the gtk_snapshot_push() and gtk_snapshot_pop() functions to
  * change the current node.
  *
  * The only way to obtain a #GtkSnapshot object is as an argument to
@@ -58,7 +58,6 @@ gtk_snapshot_state_new (GtkSnapshotState *parent,
 
   state->node = node;
   state->parent = parent;
-  graphene_matrix_init_identity (&state->transform);
 
   return state;
 }
@@ -69,33 +68,6 @@ gtk_snapshot_state_free (GtkSnapshotState *state)
   g_slice_free (GtkSnapshotState, state);
 }
 
-static void
-gtk_snapshot_state_set_transform (GtkSnapshotState        *state,
-                                  const graphene_matrix_t *transform)
-{
-  graphene_matrix_init_from_matrix (&state->transform, transform);
-
-  state->world_is_valid = FALSE;
-}
-
-static const graphene_matrix_t *
-gtk_snapshot_state_get_world_transform (GtkSnapshotState *state)
-{
-  if (!state->world_is_valid)
-    {
-      if (state->parent)
-        graphene_matrix_multiply (gtk_snapshot_state_get_world_transform (state->parent),
-                                  &state->transform,
-                                  &state->world_transform);
-      else
-        graphene_matrix_init_from_matrix (&state->world_transform, &state->transform);
-
-      state->world_is_valid = TRUE;
-    }
-
-  return &state->world_transform;
-}
-
 void
 gtk_snapshot_init (GtkSnapshot          *snapshot,
                    GskRenderer          *renderer,
@@ -147,8 +119,8 @@ gtk_snapshot_finish (GtkSnapshot *snapshot)
  * @snapshot: a #GtkSnapshot
  * @node: the render node to push
  *
- * Appends @node to the current render node of @snapshot,
- * and makes @node the new current render node.
+ * Makes @node the new current render node. You are responsible for adding
+ * @node to the snapshot.
  *
  * Since: 3.90
  */
@@ -158,8 +130,6 @@ gtk_snapshot_push_node (GtkSnapshot   *snapshot,
 {
   g_return_if_fail (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE);
 
-  gtk_snapshot_append_node (snapshot, node);
-
   snapshot->state = gtk_snapshot_state_new (snapshot->state, node);
 }
 
@@ -198,6 +168,7 @@ gtk_snapshot_push (GtkSnapshot           *snapshot,
       g_free (str);
     }
 
+  gtk_snapshot_append_node (snapshot, node);
   gtk_snapshot_push_node (snapshot, node);
   gsk_render_node_unref (node);
 }
@@ -246,65 +217,51 @@ gtk_snapshot_get_renderer (const GtkSnapshot *snapshot)
 }
 
 /**
- * gtk_snapshot_set_transform:
- * @snapshot: a #GtkSnapshot
- * @transform: a transformation matrix
+ * gtk_snapshot_translate_2d:
+ * @snapshot: a $GtkSnapshot
+ * @x: horizontal translation
+ * @y: vertical translation
  *
- * Replaces the current transformation with the given @transform.
+ * Appends a translation by (@x, @y) to the current transformation.
  *
  * Since: 3.90
  */
 void
-gtk_snapshot_set_transform (GtkSnapshot             *snapshot,
-                            const graphene_matrix_t *transform)
+gtk_snapshot_translate_2d (GtkSnapshot *snapshot,
+                           int          x,
+                           int          y)
 {
-  g_return_if_fail (snapshot->state != NULL);
-
-  gtk_snapshot_state_set_transform (snapshot->state, transform);
+  snapshot->state->translate_x += x;
+  snapshot->state->translate_y += y;
 }
 
 /**
- * gtk_snapshot_transform:
+ * gtk_snapshot_get_offset:
  * @snapshot: a #GtkSnapshot
- * @transform: a transformation matrix
+ * @x: (out allow-none): return location for x offset
+ * @y: (out allow-none): return location for y offset
  *
- * Appends @transform to the current transformation.
- *
- * Since: 3.90
- */
-void
-gtk_snapshot_transform (GtkSnapshot             *snapshot,
-                        const graphene_matrix_t *transform)
-{
-  graphene_matrix_t result;
-
-  g_return_if_fail (snapshot->state != NULL);
-
-  graphene_matrix_multiply (transform, &snapshot->state->transform, &result);
-  gtk_snapshot_state_set_transform (snapshot->state, &result);
-}
-
-/**
- * gtk_snapshot_translate_2d:
- * @snapshot: a $GtkSnapshot
- * @x: horizontal translation
- * @y: vertical translation
+ * Queries the offset managed by @snapshot. This offset is the
+ * accumulated sum of calls to gtk_snapshot_translate_2d().
  *
- * Appends a translation by (@x, @y) to the current transformation.
+ * Use this offset to determine how to offset nodes that you
+ * manually add to the snapshot using
+ * gtk_snapshot_append_node().
  *
- * Since: 3.90
- */
+ * Note that other functions that add nodes for you, such as
+ * gtk_snapshot_append_cairo_node() will add this offset for
+ * you.
+ **/
 void
-gtk_snapshot_translate_2d (GtkSnapshot *snapshot,
-                           int          x,
-                           int          y)
+gtk_snapshot_get_offset (GtkSnapshot *snapshot,
+                         double      *x,
+                         double      *y)
 {
-  graphene_matrix_t transform;
-  graphene_point3d_t point;
+  if (x)
+    *x = snapshot->state->translate_x;
 
-  graphene_point3d_init (&point, x, y, 0);
-  graphene_matrix_init_translate (&transform, &point);
-  gtk_snapshot_transform (snapshot, &transform);
+  if (y)
+    *y = snapshot->state->translate_y;
 }
 
 /**
@@ -327,7 +284,6 @@ gtk_snapshot_append_node (GtkSnapshot   *snapshot,
   if (snapshot->state)
     {
       gsk_container_node_append_child (snapshot->state->node, node);
-      gsk_render_node_set_transform (node, &snapshot->state->transform);
     }
   else
     {
@@ -357,11 +313,14 @@ gtk_snapshot_append_cairo_node (GtkSnapshot           *snapshot,
                                 ...)
 {
   GskRenderNode *node;
+  graphene_rect_t real_bounds;
+  cairo_t *cr;
 
   g_return_val_if_fail (snapshot != NULL, NULL);
   g_return_val_if_fail (bounds != NULL, NULL);
 
-  node = gsk_cairo_node_new (bounds);
+  graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds);
+  node = gsk_cairo_node_new (&real_bounds);
 
   if (name)
     {
@@ -380,7 +339,11 @@ gtk_snapshot_append_cairo_node (GtkSnapshot           *snapshot,
   gtk_snapshot_append_node (snapshot, node);
   gsk_render_node_unref (node);
 
-  return gsk_cairo_node_get_draw_context (node, snapshot->renderer);
+  cr = gsk_cairo_node_get_draw_context (node, snapshot->renderer);
+
+  cairo_translate (cr, snapshot->state->translate_x, snapshot->state->translate_y);
+
+  return cr;
 }
 
 static void
@@ -408,22 +371,11 @@ gboolean
 gtk_snapshot_clips_rect (GtkSnapshot           *snapshot,
                          const graphene_rect_t *bounds)
 {
+  graphene_rect_t offset_bounds;
   cairo_rectangle_int_t rect;
 
-  if (snapshot->state)
-    {
-      const graphene_matrix_t *world;
-      graphene_rect_t transformed;
-
-      world = gtk_snapshot_state_get_world_transform (snapshot->state);
-
-      graphene_matrix_transform_bounds (world, bounds, &transformed);
-      rectangle_init_from_graphene (&rect, &transformed);
-    }
-  else
-    {
-      rectangle_init_from_graphene (&rect, bounds);
-    }
+  graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, 
&offset_bounds);
+  rectangle_init_from_graphene (&rect, &offset_bounds);
 
   return cairo_region_contains_rectangle (snapshot->clip_region, &rect) == CAIRO_REGION_OVERLAP_OUT;
 }
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index e79d713..6acb5aa 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -50,15 +50,13 @@ GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_pop                        (GtkSnapshot            *snapshot);
 
 GDK_AVAILABLE_IN_3_90
-void            gtk_snapshot_set_transform              (GtkSnapshot            *snapshot,
-                                                         const graphene_matrix_t *transform);
-GDK_AVAILABLE_IN_3_90
-void            gtk_snapshot_transform                  (GtkSnapshot            *snapshot,
-                                                         const graphene_matrix_t *transform);
-GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_translate_2d               (GtkSnapshot            *snapshot,
                                                          int                     x,
                                                          int                     y);
+GDK_AVAILABLE_IN_3_90
+void            gtk_snapshot_get_offset                 (GtkSnapshot            *snapshot,
+                                                         double                 *x,
+                                                         double                 *y);
 
 GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_append_node                (GtkSnapshot            *snapshot,
diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h
index 2f70962..74fbf9f 100644
--- a/gtk/gtksnapshotprivate.h
+++ b/gtk/gtksnapshotprivate.h
@@ -29,9 +29,8 @@ struct _GtkSnapshotState {
 
   GskRenderNode         *node;
 
-  graphene_matrix_t      transform;
-  graphene_matrix_t      world_transform;
-  guint                  world_is_valid : 1;
+  double                 translate_x;
+  double                 translate_y;
 };
 
 struct _GtkSnapshot {
@@ -49,12 +48,6 @@ void            gtk_snapshot_init               (GtkSnapshot             *state,
                                                  ...) G_GNUC_PRINTF (4, 5);
 GskRenderNode * gtk_snapshot_finish             (GtkSnapshot             *state);
 
-static inline const graphene_matrix_t *
-gtk_snapshot_get_transform (const GtkSnapshot *snapshot)
-{
-  return &snapshot->state->transform;
-}
-
 G_END_DECLS
 
 #endif /* __GTK_SNAPSHOT_PRIVATE_H__ */
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index 5f15586..8bfbfe2 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -525,6 +525,10 @@ append_node (GtkTreeModelRenderNode *nodemodel,
       /* no children */
       break;
 
+    case GSK_TRANSFORM_NODE:
+      append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1);
+      break;
+
     case GSK_CONTAINER_NODE:
       {
         gint elt_index;
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 11a0b10..659921c 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -132,36 +132,13 @@ static void
 populate_render_node_properties (GtkListStore  *store,
                                  GskRenderNode *node)
 {
-  graphene_matrix_t m;
   graphene_rect_t bounds;
-  GString *s;
   int i;
   char *tmp;
   GEnumClass *class;
 
   gtk_list_store_clear (store);
 
-  gsk_render_node_get_transform (node, &m);
-
-  s = g_string_new ("");
-  for (i = 0; i < 4; i++)
-    {
-      if (i > 0)
-        g_string_append (s, "\n");
-      g_string_append_printf (s, "| %+.6f %+.6f %+.6f %+.6f |",
-                              graphene_matrix_get_value (&m, i, 0),
-                              graphene_matrix_get_value (&m, i, 1),
-                              graphene_matrix_get_value (&m, i, 2),
-                              graphene_matrix_get_value (&m, i, 3));
-    }
-
-  gtk_list_store_insert_with_values (store, NULL, -1,
-                                     0, "Transform",
-                                     1, s->str,
-                                     -1);
-
-  g_string_free (s, TRUE);
-
   gsk_render_node_get_bounds (node, &bounds);
 
   tmp = g_strdup_printf ("%.6f x %.6f + %.6f + %.6f",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]