summaryrefslogtreecommitdiff
path: root/gsk
diff options
context:
space:
mode:
authorTimm Bäder <mail@baedert.org>2020-05-24 12:06:07 +0200
committerTimm Bäder <mail@baedert.org>2020-05-24 15:59:05 +0200
commitd5bf3c2cd13b711487ce1bfcd7ef57222583ee54 (patch)
tree7be9f3873cb8edc4a41cb258fd884b0a91cd9c6d /gsk
parent094788f1a37e090ffab3ffb37c380dae764e2252 (diff)
downloadgtk+-d5bf3c2cd13b711487ce1bfcd7ef57222583ee54.tar.gz
gl renderer: Improve clipping code
don't render a clip to a texture if the new clip does not intersect with any of the corners of the currently rounded clip. Fixes #2770
Diffstat (limited to 'gsk')
-rw-r--r--gsk/gl/glutilsprivate.h30
-rw-r--r--gsk/gl/gskglrenderer.c127
2 files changed, 120 insertions, 37 deletions
diff --git a/gsk/gl/glutilsprivate.h b/gsk/gl/glutilsprivate.h
index c2a67796b0..f035bda26e 100644
--- a/gsk/gl/glutilsprivate.h
+++ b/gsk/gl/glutilsprivate.h
@@ -4,6 +4,36 @@
#define SANITY_CHECKS 0
+
+#define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
+ r->bounds.origin.y, \
+ r->corner[0].width, r->corner[0].height))
+
+#define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
+ r->bounds.origin.y, \
+ r->corner[1].width, r->corner[1].height))
+
+#define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
+ r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
+ r->corner[2].width, r->corner[2].height))
+
+#define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
+ r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
+ r->corner[3].width, r->corner[3].height))
+
+
+#define rounded_rect_corner0(r) rounded_rect_top_left(r)
+#define rounded_rect_corner1(r) rounded_rect_top_right(r)
+#define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
+#define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
+
+#define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
+#define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
+#define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
+
+#define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
+ _y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
+
enum {
NINE_SLICE_TOP_LEFT = 0,
NINE_SLICE_TOP_CENTER = 1,
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 8212ca30fd..a451338d59 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1159,59 +1159,112 @@ render_clipped_child (GskGLRenderer *self,
GskRenderNode *child)
{
graphene_rect_t transformed_clip;
- graphene_rect_t intersection;
GskRoundedRect child_clip;
ops_transform_bounds_modelview (builder, clip, &transformed_clip);
if (builder->clip_is_rectilinear)
- {
- /* Simple case: */
- graphene_rect_intersection (&transformed_clip,
- &builder->current_clip->bounds,
- &intersection);
+ goto trivial;
- gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
+ {
+ const GskRoundedRect *cur_clip = builder->current_clip;
+ int n_corners = 0;
+ bool corners[4];
+
+ /* Intersects with top left corner? */
+ n_corners += corners[0] = rounded_rect_has_corner (cur_clip, 0) &&
+ graphene_rect_intersection (&transformed_clip,
+ &rounded_rect_corner (cur_clip, 0), NULL);
+ /* top right? */
+ n_corners += corners[1] = rounded_rect_has_corner (cur_clip, 1) &&
+ graphene_rect_intersection (&transformed_clip,
+ &rounded_rect_corner (cur_clip, 1), NULL);
+ /* bottom right? */
+ n_corners += corners[2] = rounded_rect_has_corner (cur_clip, 2) &&
+ graphene_rect_intersection (&transformed_clip,
+ &rounded_rect_corner (cur_clip, 2), NULL);
+ /* bottom left */
+ n_corners += corners[3] = rounded_rect_has_corner (cur_clip, 3) &&
+ graphene_rect_intersection (&transformed_clip,
+ &rounded_rect_corner (cur_clip, 3), NULL);
+
+ if (n_corners == 0)
+ goto trivial;
+
+ if (corners[0] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 0)))
+ goto rtt;
+ if (corners[1] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 1)))
+ goto rtt;
+ if (corners[2] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 2)))
+ goto rtt;
+ if (corners[3] && !graphene_rect_contains_rect (&transformed_clip, &rounded_rect_corner (cur_clip, 3)))
+ goto rtt;
+
+ /* We do intersect with at least one of the corners, but in such a way that the
+ * intersection between the two clips can still be represented by a single rounded
+ * rect in a trivial way. do that. */
+ {
+ GskRoundedRect real_intersection;
+
+ graphene_rect_intersection (&transformed_clip, &cur_clip->bounds, &real_intersection.bounds);
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (corners[i])
+ real_intersection.corner[i] = cur_clip->corner[i];
+ else
+ real_intersection.corner[i].width = real_intersection.corner[i].height = 0;
+ }
- ops_push_clip (builder, &child_clip);
+ /* Draw with that new clip */
+ ops_push_clip (builder, &real_intersection);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_clip (builder);
- return;
}
+ return;
+ }
- /* Intersection might end up having rounded corners again */
- if (!rounded_inner_rect_contains_rect (builder->current_clip,
- &transformed_clip))
- {
- /* well fuck */
- const float scale = ops_get_scale (builder);
- gboolean is_offscreen;
- TextureRegion region;
- GskRoundedRect scaled_clip;
-
- memset (&scaled_clip, 0, sizeof (GskRoundedRect));
-
- scaled_clip.bounds.origin.x = clip->origin.x * scale;
- scaled_clip.bounds.origin.y = clip->origin.y * scale;
- scaled_clip.bounds.size.width = clip->size.width * scale;
- scaled_clip.bounds.size.height = clip->size.height * scale;
+rtt:
+ {
+ /* well fuck */
+ const float scale = ops_get_scale (builder);
+ gboolean is_offscreen;
+ TextureRegion region;
+ GskRoundedRect scaled_clip;
+
+ memset (&scaled_clip, 0, sizeof (GskRoundedRect));
+
+ scaled_clip.bounds.origin.x = clip->origin.x * scale;
+ scaled_clip.bounds.origin.y = clip->origin.y * scale;
+ scaled_clip.bounds.size.width = clip->size.width * scale;
+ scaled_clip.bounds.size.height = clip->size.height * scale;
+
+ ops_push_clip (builder, &scaled_clip);
+ if (!add_offscreen_ops (self, builder, &child->bounds,
+ child,
+ &region, &is_offscreen,
+ RESET_OPACITY | FORCE_OFFSCREEN))
+ g_assert_not_reached ();
+ ops_pop_clip (builder);
- ops_push_clip (builder, &scaled_clip);
- if (!add_offscreen_ops (self, builder, &child->bounds,
- child,
- &region, &is_offscreen,
- RESET_OPACITY | FORCE_OFFSCREEN))
- g_assert_not_reached ();
- ops_pop_clip (builder);
+ ops_set_program (builder, &self->programs->blit_program);
+ ops_set_texture (builder, region.texture_id);
+ load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
+ return;
+ }
- ops_set_program (builder, &self->programs->blit_program);
- ops_set_texture (builder, region.texture_id);
- load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
- return;
- }
+trivial:
+ memset (&child_clip, 0, sizeof (GskRoundedRect));
+ graphene_rect_intersection (&transformed_clip,
+ &builder->current_clip->bounds,
+ &child_clip.bounds);
+ ops_push_clip (builder, &child_clip);
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ ops_pop_clip (builder);
+ return;
}
static inline void