summaryrefslogtreecommitdiff
path: root/gsk/gl/gskglrenderer.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsk/gl/gskglrenderer.c')
-rw-r--r--gsk/gl/gskglrenderer.c302
1 files changed, 181 insertions, 121 deletions
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 130971e7b9..9df466a248 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -70,7 +70,6 @@ typedef enum
RESET_CLIP = 1 << 1,
RESET_OPACITY = 1 << 2,
DUMP_FRAMEBUFFER = 1 << 3,
- CENTER_CHILD = 1 << 4,
NO_CACHE_PLZ = 1 << 5,
} OffscreenFlags;
@@ -906,6 +905,7 @@ upload_texture (GskGLRenderer *self,
}
else
{
+
out_region->texture_id =
gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture,
@@ -1152,6 +1152,59 @@ rounded_inner_rect_contains_rect (const GskRoundedRect *rounded,
return graphene_rect_contains_rect (&inner, rect);
}
+/* Current clip is NOT rounded but new one is definitely! */
+static inline bool
+intersect_rounded_rectilinear (const graphene_rect_t *non_rounded,
+ const GskRoundedRect *rounded,
+ GskRoundedRect *result)
+{
+ int n_corners = 0;
+ bool corners[4];
+
+ /* Intersects with top left corner? */
+ n_corners += corners[0] = rounded_rect_has_corner (rounded, 0) &&
+ graphene_rect_intersection (non_rounded,
+ &rounded_rect_corner (rounded, 0), NULL);
+ /* top right? */
+ n_corners += corners[1] = rounded_rect_has_corner (rounded, 1) &&
+ graphene_rect_intersection (non_rounded,
+ &rounded_rect_corner (rounded, 1), NULL);
+ /* bottom right? */
+ n_corners += corners[2] = rounded_rect_has_corner (rounded, 2) &&
+ graphene_rect_intersection (non_rounded,
+ &rounded_rect_corner (rounded, 2), NULL);
+ /* bottom left */
+ n_corners += corners[3] = rounded_rect_has_corner (rounded, 3) &&
+ graphene_rect_intersection (non_rounded,
+ &rounded_rect_corner (rounded, 3), NULL);
+
+ if (corners[0] && !graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 0)))
+ return false;
+ if (corners[1] && !graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 1)))
+ return false;
+ if (corners[2] && !graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 2)))
+ return false;
+ if (corners[3] && !graphene_rect_contains_rect (non_rounded, &rounded_rect_corner (rounded, 3)))
+ return false;
+
+ /* 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. */
+ graphene_rect_intersection (non_rounded, &rounded->bounds, &result->bounds);
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (corners[i])
+ result->corner[i] = rounded->corner[i];
+ else
+ result->corner[i].width = result->corner[i].height = 0;
+ }
+
+ return true;
+}
+
+/* This code intersects the current (maybe rounded) clip with the new
+ * non-rounded clip */
static inline void
render_clipped_child (GskGLRenderer *self,
RenderOpBuilder *builder,
@@ -1159,112 +1212,57 @@ render_clipped_child (GskGLRenderer *self,
GskRenderNode *child)
{
graphene_rect_t transformed_clip;
- GskRoundedRect child_clip;
+ GskRoundedRect intersection;
ops_transform_bounds_modelview (builder, clip, &transformed_clip);
if (builder->clip_is_rectilinear)
- goto trivial;
-
- {
- 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;
- }
+ {
+ memset (&intersection, 0, sizeof (GskRoundedRect));
+ graphene_rect_intersection (&transformed_clip,
+ &builder->current_clip->bounds,
+ &intersection.bounds);
- /* Draw with that new clip */
- ops_push_clip (builder, &real_intersection);
+ ops_push_clip (builder, &intersection);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_clip (builder);
}
- return;
- }
-
-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);
+ else if (intersect_rounded_rectilinear (&transformed_clip,
+ builder->current_clip,
+ &intersection))
+ {
+ ops_push_clip (builder, &intersection);
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ ops_pop_clip (builder);
+ }
+ else
+ {
+ /* well fuck */
+ const float scale = ops_get_scale (builder);
+ gboolean is_offscreen;
+ TextureRegion region;
+ GskRoundedRect scaled_clip;
- ops_set_program (builder, &self->programs->blit_program);
- ops_set_texture (builder, region.texture_id);
+ memset (&scaled_clip, 0, sizeof (GskRoundedRect));
- load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
- return;
- }
+ 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);
-trivial:
- memset (&child_clip, 0, sizeof (GskRoundedRect));
- graphene_rect_intersection (&transformed_clip,
- &builder->current_clip->bounds,
- &child_clip.bounds);
+ ops_set_program (builder, &self->programs->blit_program);
+ ops_set_texture (builder, region.texture_id);
- ops_push_clip (builder, &child_clip);
- gsk_gl_renderer_add_render_ops (self, child, builder);
- ops_pop_clip (builder);
- return;
+ load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder);
+ }
}
static inline void
@@ -1294,6 +1292,29 @@ render_rounded_clip_node (GskGLRenderer *self,
return;
ops_transform_bounds_modelview (builder, &clip->bounds, &transformed_clip.bounds);
+ for (i = 0; i < 4; i ++)
+ {
+ transformed_clip.corner[i].width = clip->corner[i].width * scale;
+ transformed_clip.corner[i].height = clip->corner[i].height * scale;
+ }
+
+ if (builder->clip_is_rectilinear)
+ {
+ GskRoundedRect intersected_clip;
+
+ if (intersect_rounded_rectilinear (&builder->current_clip->bounds,
+ &transformed_clip,
+ &intersected_clip))
+ {
+ ops_push_clip (builder, &intersected_clip);
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ ops_pop_clip (builder);
+ return;
+ }
+ }
+
+ /* After this point we are really working with a new and a current clip
+ * which both have rounded corners. */
if (!ops_has_clip (builder))
need_offscreen = FALSE;
@@ -1307,12 +1328,16 @@ render_rounded_clip_node (GskGLRenderer *self,
{
/* If they don't intersect at all, we can simply set
* the new clip and add the render ops */
- for (i = 0; i < 4; i ++)
+
+ /* If the new clip entirely contains the current clip, the intersection is simply
+ * the current clip, so we can ignore the new one */
+ if (rounded_inner_rect_contains_rect (&transformed_clip, &builder->current_clip->bounds))
{
- transformed_clip.corner[i].width = clip->corner[i].width * scale;
- transformed_clip.corner[i].height = clip->corner[i].height * scale;
+ gsk_gl_renderer_add_render_ops (self, child, builder);
+ return;
}
+ /* TODO: Intersect current and new clip */
ops_push_clip (builder, &transformed_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_clip (builder);
@@ -1354,7 +1379,6 @@ render_rounded_clip_node (GskGLRenderer *self,
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
}
- /* Else this node is entirely out of the current clip node and we don't draw it anyway. */
}
static inline void
@@ -1762,7 +1786,6 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self,
}
-
static GdkRGBA COLOR_WHITE = { 1, 1, 1, 1 };
static inline void
render_outset_shadow_node (GskGLRenderer *self,
@@ -1783,19 +1806,32 @@ render_outset_shadow_node (GskGLRenderer *self,
OpShadow *shadow;
int blurred_texture_id;
int cached_tid;
+ bool do_slicing;
/* scaled_outline is the minimal outline we need to draw the given drop shadow,
* enlarged by the spread and offset by the blur radius. */
scaled_outline = *outline;
- /* Shrink our outline to the minimum size that can still hold all the border radii */
- gsk_rounded_rect_shrink_to_minimum (&scaled_outline);
- /* Increase by the spread */
- gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
- /* Grow bounds but don't grow corners */
- graphene_rect_inset (&scaled_outline.bounds, - extra_blur_pixels, - extra_blur_pixels);
- /* For the center part, we add a few pixels */
- scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
- scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
+
+ if (outline->bounds.size.width < blur_extra ||
+ outline->bounds.size.height < blur_extra)
+ {
+ do_slicing = false;
+ gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
+ }
+ else
+ {
+ /* Shrink our outline to the minimum size that can still hold all the border radii */
+ gsk_rounded_rect_shrink_to_minimum (&scaled_outline);
+ /* Increase by the spread */
+ gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread);
+ /* Grow bounds but don't grow corners */
+ graphene_rect_inset (&scaled_outline.bounds, - blur_extra / 2.0, - blur_extra / 2.0);
+ /* For the center part, we add a few pixels */
+ scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
+ scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
+
+ do_slicing = true;
+ }
texture_width = (int)ceil ((scaled_outline.bounds.size.width + blur_extra) * scale);
texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale);
@@ -1880,6 +1916,41 @@ render_outset_shadow_node (GskGLRenderer *self,
blurred_texture_id = cached_tid;
}
+
+ if (!do_slicing)
+ {
+ const float min_x = floorf (builder->dx + outline->bounds.origin.x - spread - (blur_extra / 2.0) + dx);
+ const float min_y = floorf (builder->dy + outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy);
+ float x1, x2, y1, y2, tx1, tx2, ty1, ty2;
+
+ ops_set_program (builder, &self->programs->outset_shadow_program);
+ ops_set_color (builder, color);
+ ops_set_texture (builder, blurred_texture_id);
+
+ shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW);
+ shadow->outline = transform_rect (self, builder, outline);
+
+ tx1 = 0; tx2 = 1;
+ ty1 = 0; ty2 = 1;
+
+ x1 = min_x;
+ x2 = min_x + texture_width / scale;
+ y1 = min_y;
+ y2 = min_y + texture_height / scale;
+
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+ return;
+ }
+
+
ops_set_program (builder, &self->programs->outset_shadow_program);
ops_set_color (builder, color);
ops_set_texture (builder, blurred_texture_id);
@@ -3317,19 +3388,8 @@ add_offscreen_ops (GskGLRenderer *self,
bounds->origin.y * scale,
width, height));
- if (flags & CENTER_CHILD)
- {
- ops_offset (builder,
- (bounds->size.width - child_node->bounds.size.width) / 2.0 -
- child_node->bounds.origin.x,
- (bounds->size.height - child_node->bounds.size.height) / 2.0 -
- child_node->bounds.origin.y);
- }
- else
- {
- builder->dx = 0;
- builder->dy = 0;
- }
+ builder->dx = 0;
+ builder->dy = 0;
if (flags & RESET_OPACITY)
prev_opacity = ops_set_opacity (builder, 1.0);