wlroots/include/util/rect_union.h
Kenny Levinsen 57441ded02 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 <kl@kl.wtf>
2026-05-01 12:50:04 +00:00

78 lines
2.5 KiB
C

#ifndef UTIL_RECT_UNION_H
#define UTIL_RECT_UNION_H
#include <stdlib.h>
#include <stdbool.h>
#include <pixman.h>
#include <wayland-util.h>
/**
* `struct rect_union` is a data structure to efficiently accumulate a number
* of rectangles and then, when needed, compute a disjoint cover of their union.
* (That is: produce a list of disjoint rectangles which covers every point
* that was contained in one of the added rectangles.)
*
* Add rectangles to the union with `rect_union_add()`; to compute the disjoint
* union, run `rect_union_evaluate()`, which will place the result in `.region`.
* If there were any allocation failures, `.region` will instead contain the
* bounding box for the entire list of rectangles.
*
* Example usage:
*
* struct rect_union r;
* rect_union_init(&r);
* for (j in ...) {
* rect_union_add(&r, box[j]);
* }
* const pixman_region32_t *reg = rect_union_evaluate(&r);
* int nboxes;
* pixman_box32_t *boxes = pixman_region32_rectangles(reg, nboxes);
* for (int i = 0; i < nboxes; i++) {
* do_stuff(boxes[i]);
* }
* rect_union_destroy(&r);
*
*/
struct rect_union {
pixman_box32_t bounding_box; // Always up-to-date bounding box
pixman_region32_t region; // Updated only on _evaluate()
struct wl_array unsorted; // pixman_box32_t
bool alloc_failure; // If this is true, fall back to computing a bounding box
};
/**
* Initialize *r, disregarding any previous contents.
*/
void rect_union_init(struct rect_union *r);
/**
* Free heap data associated with *r; should only be called after rect_union_init.
* Leaves *r in an invalid state.
*/
void rect_union_finish(struct rect_union *r);
/**
* Add a rectangle to the union. If `box` is empty or invalid (x2 > x1 || y2 > y1),
* do nothing.
*
* Amortized time: O(1)
*/
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.
*
* 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().
*
* Worst case time: O(t^2), where t is the number of rectangles in the list.
* Best case time: O(t), if rectangles are disjoint and have y-x band structure
*/
const pixman_region32_t *rect_union_evaluate(struct rect_union *r);
#endif