gl renderer: Draw rounded clip child to a texture
authorTimm Bäder <mail@baedert.org>
Wed, 14 Mar 2018 11:36:32 +0000 (12:36 +0100)
committerTimm Bäder <mail@baedert.org>
Wed, 14 Mar 2018 16:28:41 +0000 (17:28 +0100)
And then clip the texture using the current (maybe also rounded) clip.
This way, the result is correct. We don't necessarily have to do the
offscreen drawing in any case, but got the safe route for now.

gsk/gl/gskglrenderer.c

index 8a4aa9393bd587d88a3bc4974828a69e5fb5de2c..4b01f70383bcefcd1eaff3115917d238b4e442ed 100644 (file)
@@ -172,7 +172,8 @@ static void add_offscreen_ops                 (GskGLRenderer   *self,
                                                GskRenderNode   *child_node,
                                                int             *texture_id,
                                                gboolean        *is_offscreen,
-                                               gboolean         force_offscreen);
+                                               gboolean         force_offscreen,
+                                               gboolean         reset_clip);
 static void gsk_gl_renderer_add_render_ops     (GskGLRenderer   *self,
                                                 GskRenderNode   *node,
                                                 RenderOpBuilder *builder);
@@ -779,20 +780,43 @@ render_clip_node (GskGLRenderer   *self,
 }
 
 static inline void
-render_rounded_clip_node (GskGLRenderer   *self,
-                          GskRenderNode   *node,
-                          RenderOpBuilder *builder)
+render_rounded_clip_node (GskGLRenderer       *self,
+                          GskRenderNode       *node,
+                          RenderOpBuilder     *builder)
 {
+  const float min_x = node->bounds.origin.x;
+  const float min_y = node->bounds.origin.y;
+  const float max_x = min_x + node->bounds.size.width;
+  const float max_y = min_y + node->bounds.size.height;
+  const GskRoundedRect *child_clip = gsk_rounded_clip_node_peek_clip (node);
   GskRoundedRect prev_clip;
   GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
-  const GskRoundedRect *rounded_clip = gsk_rounded_clip_node_peek_clip (node);
-  GskRoundedRect child_clip;
+  int texture_id;
+  gboolean is_offscreen;
 
-  rounded_rect_intersect (self, builder, rounded_clip, &child_clip);
+  /* NOTE: We are *not* transforming the clip by the current modelview here.
+   *       We instead draw the untransformed clip to a texture and then transform
+   *       that texture.
+   */
+
+  prev_clip = ops_set_clip (builder, child_clip);
+  add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
+                     child,
+                     &texture_id, &is_offscreen, TRUE, FALSE);
 
-  prev_clip = ops_set_clip (builder, &child_clip);
-  gsk_gl_renderer_add_render_ops (self, child, builder);
   ops_set_clip (builder, &prev_clip);
+  ops_set_program (builder, &self->blit_program);
+  ops_set_texture (builder, texture_id);
+
+  ops_draw (builder, (GskQuadVertex[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 }, },
+  });
 }
 
 static inline void
@@ -810,7 +834,7 @@ render_color_matrix_node (GskGLRenderer       *self,
 
   add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
                      gsk_color_matrix_node_get_child (node),
-                     &texture_id, &is_offscreen, FALSE);
+                     &texture_id, &is_offscreen, FALSE, TRUE);
 
   ops_set_program (builder, &self->color_matrix_program);
   ops_set_color_matrix (builder,
@@ -854,7 +878,7 @@ render_blur_node (GskGLRenderer       *self,
   RenderOp op;
   add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y,
                      gsk_blur_node_get_child (node),
-                     &texture_id, &is_offscreen, FALSE);
+                     &texture_id, &is_offscreen, FALSE, TRUE);
 
   ops_set_program (builder, &self->blur_program);
   op.op = OP_CHANGE_BLUR;
@@ -1359,7 +1383,7 @@ render_shadow_node (GskGLRenderer       *self,
       /* Draw the child offscreen, without the offset. */
       add_offscreen_ops (self, builder,
                          min_x, max_x, min_y, max_y,
-                         shadow_child, &texture_id, &is_offscreen, FALSE);
+                         shadow_child, &texture_id, &is_offscreen, FALSE, TRUE);
 
       ops_offset (builder, dx, dy);
       ops_set_program (builder, &self->shadow_program);
@@ -1431,10 +1455,10 @@ render_cross_fade_node (GskGLRenderer       *self,
    * start and the end node might be a lot smaller than that. */
 
   add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, start_node,
-                     &start_texture_id, &is_offscreen1, TRUE);
+                     &start_texture_id, &is_offscreen1, TRUE, TRUE);
 
   add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, end_node,
-                     &end_texture_id, &is_offscreen2, TRUE);
+                     &end_texture_id, &is_offscreen2, TRUE, TRUE);
 
   ops_set_program (builder, &self->cross_fade_program);
   op.op = OP_CHANGE_CROSS_FADE;
@@ -2193,7 +2217,8 @@ add_offscreen_ops (GskGLRenderer   *self,
                    GskRenderNode   *child_node,
                    int             *texture_id,
                    gboolean        *is_offscreen,
-                   gboolean         force_offscreen)
+                   gboolean         force_offscreen,
+                   gboolean         reset_clip)
 {
   const float width = (max_x - min_x) * self->scale_factor;
   const float height = (max_y - min_y) * self->scale_factor;
@@ -2244,12 +2269,15 @@ add_offscreen_ops (GskGLRenderer   *self,
   prev_modelview = ops_set_modelview (builder, &identity);
   prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (min_x, min_y,
                                                                   width, height));
-  prev_clip = ops_set_clip (builder,
-                            &GSK_ROUNDED_RECT_INIT (min_x, min_y, width, height));
+  if (reset_clip)
+    prev_clip = ops_set_clip (builder,
+                              &GSK_ROUNDED_RECT_INIT (min_x, min_y, width, height));
 
   gsk_gl_renderer_add_render_ops (self, child_node, builder);
 
-  ops_set_clip (builder, &prev_clip);
+  if (reset_clip)
+    ops_set_clip (builder, &prev_clip);
+
   ops_set_viewport (builder, &prev_viewport);
   ops_set_modelview (builder, &prev_modelview);
   ops_set_projection (builder, &prev_projection);
@@ -2551,7 +2579,7 @@ gsk_gl_renderer_render_texture (GskRenderer           *renderer,
   glGenFramebuffers (1, &fbo_id);
   glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
   glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
-  g_assert_cmpint (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
+  g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
 
   gsk_gl_renderer_clear (self);
   gsk_gl_driver_end_frame (self->gl_driver);