mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-05-29 21:38:03 -04:00
Implement "smarter" damage merging
This commit is contained in:
parent
2d11b36a24
commit
3113c1b895
1 changed files with 72 additions and 3 deletions
75
render.c
75
render.c
|
|
@ -12,6 +12,7 @@
|
|||
#include <pthread.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "pixman.h"
|
||||
#if HAS_INCLUDE(<pthread_np.h>)
|
||||
#include <pthread_np.h>
|
||||
#define pthread_setname_np(thread, name) (pthread_set_name_np(thread, name), 0)
|
||||
|
|
@ -1202,13 +1203,82 @@ draw_cursor:
|
|||
return cell_cols;
|
||||
}
|
||||
|
||||
#define MAX_REASONABLE_DAMAGE_PER_WORKER 32
|
||||
|
||||
static pixman_box32_t encompass_boxes(const pixman_box32_t* restrict b1, const pixman_box32_t* restrict b2) {
|
||||
return (pixman_box32_t){min(b1->x1, b2->x1), min(b1->y1, b2->y1), max(b1->x2, b2->x2), max(b1->y2, b2->y2)};
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Needs tuning. This is the number of damage rectangles
|
||||
* that each worker should be able to attach that then get merged
|
||||
* into the final damage region. If too many damage rectangles
|
||||
* are attached to the surface's pending buffer, performance starts to degrade,
|
||||
* or even worse, you reach an internal Wayland limit and Wayland errors
|
||||
*/
|
||||
|
||||
static void greedily_fix_damage(pixman_region32_t* damage) {
|
||||
int n_rects = 0;
|
||||
pixman_box32_t* boxes = pixman_region32_rectangles(damage, &n_rects);
|
||||
|
||||
if (likely(n_rects < MAX_REASONABLE_DAMAGE_PER_WORKER))
|
||||
return;
|
||||
|
||||
pixman_region32_t new_region;
|
||||
int num_out = 0;
|
||||
/*
|
||||
* Greedily merge damage rectangles with their right neighbor
|
||||
* if there is one.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; (i + 1) < n_rects; i += 2)
|
||||
boxes[num_out++] = encompass_boxes(&boxes[i], &boxes[i + 1]);
|
||||
|
||||
if (i < n_rects)
|
||||
boxes[num_out++] = boxes[i];
|
||||
|
||||
pixman_region32_init_rects(&new_region, boxes, num_out);
|
||||
pixman_region32_fini(damage);
|
||||
*damage = new_region;
|
||||
}
|
||||
/*
|
||||
* The maximum number of damage rectangles that any given row's
|
||||
* damage should be split into. Needs proper tuning.
|
||||
*/
|
||||
#define MAX_DAMAGE_RECTS_PER_ROW 8
|
||||
static void
|
||||
render_row(struct terminal *term, pixman_image_t *pix,
|
||||
pixman_region32_t *damage, struct row *row,
|
||||
int row_no, int cursor_col)
|
||||
{
|
||||
for (int col = term->cols - 1; col >= 0; col--)
|
||||
render_cell(term, pix, damage, row, row_no, col, cursor_col == col);
|
||||
pixman_region32_t row_damage;
|
||||
pixman_region32_init(&row_damage);
|
||||
for (int col = term->cols - 1; col >= 0; col--) {
|
||||
render_cell(term, pix, &row_damage, row, row_no, col, cursor_col == col);
|
||||
}
|
||||
int n_boxes = 0;
|
||||
pixman_box32_t* boxes = pixman_region32_rectangles(&row_damage, &n_boxes);
|
||||
|
||||
/*
|
||||
* Split the row's damage into at most MAX_DAMAGE_RECTS_PER_ROW
|
||||
* rectangles to fuse "islands" of stray cells. These stray cells
|
||||
* end up causing unnecessary remerging and less accurate damage rects.
|
||||
*
|
||||
* What makes this possible is the fact that pixman stores the rectangles
|
||||
* as a sorted array.
|
||||
*/
|
||||
int rect_count_per_rect = (n_boxes + MAX_DAMAGE_RECTS_PER_ROW - 1) / MAX_DAMAGE_RECTS_PER_ROW;
|
||||
|
||||
for (int p = 0, i = 0; p < MAX_DAMAGE_RECTS_PER_ROW; p++) {
|
||||
pixman_box32_t box = {0, 0, 0, 0};
|
||||
for (; i < min((p + 1) * rect_count_per_rect, n_boxes); i++) {
|
||||
box = encompass_boxes(&box, &boxes[i]);
|
||||
}
|
||||
pixman_region32_union_rect(damage, damage, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1);
|
||||
greedily_fix_damage(damage);
|
||||
}
|
||||
pixman_region32_fini(&row_damage);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3599,7 +3669,6 @@ grid_render(struct terminal *term)
|
|||
{
|
||||
int box_count = 0;
|
||||
pixman_box32_t *boxes = pixman_region32_rectangles(&damage, &box_count);
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
wl_surface_damage_buffer(
|
||||
term->window->surface.surf,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue