From ce042f7ba1af3f7c3ff125311c4eb82ea2e6b13c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 12 Jul 2023 11:04:25 +0200 Subject: [PATCH] vulkan: Try really hard to use clear Using clear avoids the shader engine (see last commit), so if we can get pixels out of it, we should. So we detect the overlap with the rounded corners of the clip region and emit shaders for those, but then use Clear() for the rest. With this in place, widget-factory on my integrated Intel TigerLake gets a 60% performance boost. --- gsk/gskroundedrect.c | 41 +++++++++++++++++ gsk/gskroundedrectprivate.h | 4 ++ gsk/vulkan/gskvulkanrenderpass.c | 75 ++++++++++++++++++++++++++------ 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/gsk/gskroundedrect.c b/gsk/gskroundedrect.c index 76efe4d9ae..7c1a9cc6ec 100644 --- a/gsk/gskroundedrect.c +++ b/gsk/gskroundedrect.c @@ -945,3 +945,44 @@ gsk_rounded_rect_to_string (const GskRoundedRect *self) self->corner[3].width, self->corner[3].height); } + +/* + * gsk_rounded_rect_get_largest_cover: + * @self: the rounded rect to intersect with + * @rect: the rectangle to intersect + * @result: (out caller-allocates): The resulting rectangle + * + * Computes the largest rectangle that is fully covered by both + * the given rect and the rounded rect. + * In particular, this function respects corners, so + * gsk_rounded_rect_get_largest_cover(self, &self->bounds, &rect) + * can be used to compute a decomposition for a rounded rect itself. + **/ +void +gsk_rounded_rect_get_largest_cover (const GskRoundedRect *self, + const graphene_rect_t *rect, + graphene_rect_t *result) +{ + graphene_rect_t wide, high; + double start, end; + + wide = self->bounds; + start = MAX(self->corner[GSK_CORNER_TOP_LEFT].height, self->corner[GSK_CORNER_TOP_RIGHT].height); + end = MAX(self->corner[GSK_CORNER_BOTTOM_LEFT].height, self->corner[GSK_CORNER_BOTTOM_RIGHT].height); + wide.size.height -= MIN (wide.size.height, start + end); + wide.origin.y += start; + graphene_rect_intersection (&wide, rect, &wide); + + high = self->bounds; + start = MAX(self->corner[GSK_CORNER_TOP_LEFT].width, self->corner[GSK_CORNER_BOTTOM_LEFT].width); + end = MAX(self->corner[GSK_CORNER_TOP_RIGHT].width, self->corner[GSK_CORNER_BOTTOM_RIGHT].width); + high.size.width -= MIN (high.size.width, start + end); + high.origin.x += start; + graphene_rect_intersection (&high, rect, &high); + + if (wide.size.width * wide.size.height > high.size.width * high.size.height) + *result = wide; + else + *result = high; +} + diff --git a/gsk/gskroundedrectprivate.h b/gsk/gskroundedrectprivate.h index 64c3469df9..964e0edf84 100644 --- a/gsk/gskroundedrectprivate.h +++ b/gsk/gskroundedrectprivate.h @@ -53,6 +53,10 @@ gboolean gsk_rounded_rect_equal (gconstpointer gconstpointer rect2) G_GNUC_PURE; char * gsk_rounded_rect_to_string (const GskRoundedRect *self) G_GNUC_MALLOC; +void gsk_rounded_rect_get_largest_cover (const GskRoundedRect *self, + const graphene_rect_t *rect, + graphene_rect_t *result); + typedef enum { GSK_INTERSECTION_EMPTY, GSK_INTERSECTION_NONEMPTY, diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 4d331ddfc1..51d849c1c6 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -368,21 +368,70 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self, return TRUE; /* we have handled the bounds, now do the corners */ - if (state->clip.type != GSK_VULKAN_CLIP_ROUNDED || - gsk_vulkan_clip_contains_rect (&state->clip, - graphene_point_zero (), - &GRAPHENE_RECT_INIT ( - int_clipped.x / graphene_vec2_get_x (&state->scale), - int_clipped.y / graphene_vec2_get_y (&state->scale), - int_clipped.width / graphene_vec2_get_x (&state->scale), - int_clipped.height / graphene_vec2_get_y (&state->scale) - ))) + if (state->clip.type == GSK_VULKAN_CLIP_ROUNDED) { - gsk_vulkan_clear_op (render, - &int_clipped, - color); - return TRUE; + graphene_rect_t cover; + const char *clip_type; + float scale_x = graphene_vec2_get_x (&state->scale); + float scale_y = graphene_vec2_get_y (&state->scale); + clipped = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + clip_type = gsk_vulkan_clip_get_clip_type (&state->clip, graphene_point_zero(), &clipped); + if (clip_type[0] != '\0') + { + gsk_rounded_rect_get_largest_cover (&state->clip.rect, &clipped, &cover); + int_clipped.x = ceil (cover.origin.x * scale_x); + int_clipped.y = ceil (cover.origin.y * scale_y); + int_clipped.width = floor ((cover.origin.x + cover.size.width) * scale_x) - int_clipped.x; + int_clipped.height = floor ((cover.origin.y + cover.size.height) * scale_y) - int_clipped.y; + if (int_clipped.width == 0 || int_clipped.height == 0) + { + gsk_vulkan_color_op (render, + clip_type, + &clipped, + graphene_point_zero (), + color); + return TRUE; + } + cover = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + if (clipped.origin.x != cover.origin.x) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, cover.origin.x - clipped.origin.x, clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y != cover.origin.y) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, clipped.size.width, cover.origin.y - clipped.origin.y), + graphene_point_zero (), + color); + if (clipped.origin.x + clipped.size.width != cover.origin.x + cover.size.width) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (cover.origin.x + cover.size.width, + clipped.origin.y, + clipped.origin.x + clipped.size.width - cover.origin.x - cover.size.width, + clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y + clipped.size.height != cover.origin.y + cover.size.height) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, + cover.origin.y + cover.size.height, + clipped.size.width, + clipped.origin.y + clipped.size.height - cover.origin.y - cover.size.height), + graphene_point_zero (), + color); + } } + + gsk_vulkan_clear_op (render, + &int_clipped, + color); + return TRUE; } gsk_vulkan_color_op (render, -- 2.30.2