From 57441ded02b8895ed1bb2f66c5cff6a6478307f0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 23 Apr 2026 17:15:28 +0200 Subject: [PATCH] util/rect_union: Limit rect_union_add to 1024 rects If a very large number of clip rects are accumulated in rect_union_add, rect_union_evaluate can end up being disproportionately expensive, and as an extreme numbers of clip rects are not beneficial for drawing, this is without any benefit. Limit the number of rects to 1024 in rect_union_add, switching over to bounding box mode instead when the limit is exceeded. This leads to a small 70% reduction in CPU time in the Vulkan renderer on the stacked/clip200/1024 benchmarks. Signed-off-by: Kenny Levinsen --- include/util/rect_union.h | 6 ++++-- util/rect_union.c | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/util/rect_union.h b/include/util/rect_union.h index c4b378888..297c64d43 100644 --- a/include/util/rect_union.h +++ b/include/util/rect_union.h @@ -63,8 +63,10 @@ void rect_union_add(struct rect_union *r, const pixman_box32_t *box); /** * Compute an exact cover of the rectangles added so far, and return * a pointer to a pixman_region32_t giving that cover. The pointer will - * remain valid until the next time *r is modified. If there was an allocation - * failure, this function may return a single-rectangle bounding box instead. + * remain valid until the next time *r is modified. + * + * An internal complexity limit is enforced by rect_union. If exceeded, this + * function will instead return a single-rectangle bounding box. * * This may be called multiple times and interleaved with rect_union_add(). * diff --git a/util/rect_union.c b/util/rect_union.c index 8d29798de..f113fe43e 100644 --- a/util/rect_union.c +++ b/util/rect_union.c @@ -44,13 +44,21 @@ void rect_union_add(struct rect_union *ru, const pixman_box32_t *box) { box_union(&ru->bounding_box, box); - if (!ru->alloc_failure) { - pixman_box32_t *entry = wl_array_add(&ru->unsorted, sizeof(*entry)); - if (entry) { - *entry = *box; - } else { - handle_alloc_failure(ru); - } + if (ru->alloc_failure) { + return; + } + + int nrects = (int)(ru->unsorted.size / sizeof(pixman_box32_t)); + if (nrects >= 1024) { + handle_alloc_failure(ru); + return; + } + + pixman_box32_t *entry = wl_array_add(&ru->unsorted, sizeof(*entry)); + if (entry) { + *entry = *box; + } else { + handle_alloc_failure(ru); } }