[gtk/wip/baedert/transforms6: 7/31] gl renderer: Render non-trivial transforms to a texture



commit 5907ff694fc7402982261922b1b8693efcfa3c8f
Author: Timm Bäder <mail baedert org>
Date:   Thu Nov 29 08:09:02 2018 +0100

    gl renderer: Render non-trivial transforms to a texture
    
    This way we can e.g. render rotated clips, borders, etc.

 gsk/gl/gskglrenderer.c         | 63 +++++++++++++++++++++++++++++++++++++++++-
 gsk/gl/gskglrenderops.c        | 13 +++++++++
 gsk/gl/gskglrenderopsprivate.h |  1 +
 3 files changed, 76 insertions(+), 1 deletion(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index a75f8b3823..c92b71b0f2 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -219,6 +219,31 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
                                          MAX (self->corner[2].height, self->corner[3].height)) * 2);
 }
 
+static inline gboolean
+node_supports_transform (GskRenderNode *node)
+{
+  /* Some nodes can't handle non-trivial transforms without being
+   * rendered to a texture (e.g. rotated clips, etc.). Some however
+   * work just fine, mostly because they already draw their child
+   * to a texture and just render the texture manipulated in some
+   * way, think opacity or color matrix. */
+  const guint node_type = gsk_render_node_get_node_type (node);
+
+  switch (node_type)
+    {
+      case GSK_COLOR_NODE:
+      case GSK_OPACITY_NODE:
+      case GSK_COLOR_MATRIX_NODE:
+      case GSK_TEXTURE_NODE:
+        return TRUE;
+
+      default:
+        return FALSE;
+    }
+  return FALSE;
+}
+
+
 static void gsk_gl_renderer_setup_render_mode (GskGLRenderer   *self);
 static void add_offscreen_ops                 (GskGLRenderer   *self,
                                                RenderOpBuilder *builder,
@@ -736,7 +761,43 @@ render_transform_node (GskGLRenderer   *self,
   graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv);
 
   ops_push_modelview (builder, &transformed_mv);
-  gsk_gl_renderer_add_render_ops (self, child, builder);
+  if (ops_modelview_is_simple (builder) ||
+      node_supports_transform (child))
+    {
+      gsk_gl_renderer_add_render_ops (self, child, builder);
+    }
+  else
+    {
+      const float min_x = builder->dx + child->bounds.origin.x;
+      const float min_y = builder->dy + child->bounds.origin.y;
+      const float max_x = min_x + child->bounds.size.width;
+      const float max_y = min_y + child->bounds.size.height;
+      const GskQuadVertex vertex_data[GL_N_VERTICES] = {
+        { { min_x, min_y }, { 0, 1 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+
+        { { max_x, max_y }, { 1, 0 }, },
+        { { min_x, max_y }, { 0, 0 }, },
+        { { max_x, min_y }, { 1, 1 }, },
+      };
+      int texture_id;
+      gboolean is_offscreen;
+      /* For non-trivial transforms, we draw everything on a texture and then
+       * draw the texture transformed. */
+      /* TODO: We should compute a modelview containing only the "non-trivial"
+       *       part (e.g. the rotation) and use that. We want to keep the scale
+       *       for the texture.
+       */
+      add_offscreen_ops (self, builder,
+                         min_x, max_x, min_y, max_y,
+                         child,
+                         &texture_id, &is_offscreen,
+                         FALSE, TRUE);
+      ops_set_texture (builder, texture_id);
+      ops_set_program (builder, &self->blit_program);
+      ops_draw (builder, vertex_data);
+    }
   ops_pop_modelview (builder);
 }
 
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index 1ac8f8866e..85026d8e63 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -116,6 +116,19 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder,
   graphene_rect_offset (dst, builder->dx, builder->dy);
 }
 
+gboolean
+ops_modelview_is_simple (const RenderOpBuilder *builder)
+{
+  const MatrixStackEntry *head;
+
+  g_assert (builder->mv_stack != NULL);
+  g_assert (builder->mv_stack->len >= 1);
+
+  head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
+
+  return head->metadata.simple;
+}
+
 void
 ops_set_program (RenderOpBuilder *builder,
                  const Program   *program)
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 7b0b1f824f..97ce3a28b1 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -263,6 +263,7 @@ void              ops_finish             (RenderOpBuilder         *builder);
 void              ops_push_modelview     (RenderOpBuilder         *builder,
                                           const graphene_matrix_t *mv);
 void              ops_pop_modelview      (RenderOpBuilder         *builder);
+gboolean          ops_modelview_is_simple (const RenderOpBuilder  *builder);
 float             ops_get_scale          (const RenderOpBuilder   *builder);
 
 void              ops_set_program        (RenderOpBuilder         *builder,


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