From 624fa9f8bc8bc1bf771ca6b453d64b2d1f311192 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 19 Jul 2026 01:06:21 +1000 Subject: [PATCH] [client] egl: correct surface damage reporting Apply the same sampling margin to swap damage as buffer-age repair and clip reported rectangles to the EGL surface. This ensures compositors update every pixel affected by scaling or filtering. --- client/renderers/EGL/egl.c | 74 ++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index d9fe75c2..47a0d049 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -51,8 +51,9 @@ #include "postprocess.h" #include "util.h" -#define MAX_BUFFER_AGE 3 -#define DESKTOP_DAMAGE_COUNT 4 +#define MAX_BUFFER_AGE 3 +#define DESKTOP_DAMAGE_COUNT 4 +#define DESKTOP_DAMAGE_MARGIN 1 #define MAX_ACCUMULATED_DAMAGE ((KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2) * MAX_BUFFER_AGE) #define IDX_AGO(counter, i, total) (((counter) + (total) - (i)) % (total)) @@ -1094,6 +1095,52 @@ inline static EGLint egl_bufferAge(struct Inst * this) return result; } +static FrameDamageRect egl_expandDesktopDamage( + const struct Inst * this, const FrameDamageRect * rect) +{ + const uint32_t x = rect->x > DESKTOP_DAMAGE_MARGIN ? + rect->x - DESKTOP_DAMAGE_MARGIN : 0; + const uint32_t y = rect->y > DESKTOP_DAMAGE_MARGIN ? + rect->y - DESKTOP_DAMAGE_MARGIN : 0; + const uint32_t right = (uint32_t)min((uint64_t)this->format.frameWidth, + (uint64_t)rect->x + rect->width + DESKTOP_DAMAGE_MARGIN); + const uint32_t bottom = (uint32_t)min((uint64_t)this->format.frameHeight, + (uint64_t)rect->y + rect->height + DESKTOP_DAMAGE_MARGIN); + + return (FrameDamageRect) { + .x = x, + .y = y, + .width = right > x ? right - x : 0, + .height = bottom > y ? bottom - y : 0, + }; +} + +static int egl_clipSurfaceDamage( + struct Rect * damage, int count, int width, int height) +{ + int out = 0; + for (int i = 0; i < count; ++i) + { + const int64_t x2 = (int64_t)damage[i].x + damage[i].w; + const int64_t y2 = (int64_t)damage[i].y + damage[i].h; + const int x1 = clamp(damage[i].x, 0, width); + const int y1 = clamp(damage[i].y, 0, height); + const int right = (int)clamp(x2, 0, width); + const int bottom = (int)clamp(y2, 0, height); + if (right <= x1 || bottom <= y1) + continue; + + damage[out++] = (struct Rect) { + .x = x1, + .y = y1, + .w = right - x1, + .h = bottom - y1, + }; + } + + return out; +} + inline static void renderLetterBox(struct Inst * this) { bool hLB = this->destRect.x > 0; @@ -1170,14 +1217,10 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, for (int j = 0; j < damage->count; ++j) { - struct FrameDamageRect * rect = damage->rects + j; - int x = rect->x > 0 ? rect->x - 1 : 0; - int y = rect->y > 0 ? rect->y - 1 : 0; - accumulated->rects[accumulated->count++] = (struct FrameDamageRect) { - .x = x, .y = y, - .width = min(this->format.frameWidth - x, rect->width + 2), - .height = min(this->format.frameHeight - y, rect->height + 2), - }; + const FrameDamageRect rect = + egl_expandDesktopDamage(this, damage->rects + j); + if (rect.width && rect.height) + accumulated->rects[accumulated->count++] = rect; } } } @@ -1297,12 +1340,21 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, this->width, this->height); for (int i = 0; i < desktopDamage->count; ++i) - damage[damageIdx++] = egl_desktopToScreen(matrix, desktopDamage->rects + i); + { + const FrameDamageRect rect = + egl_expandDesktopDamage(this, desktopDamage->rects + i); + if (rect.width && rect.height) + damage[damageIdx++] = egl_desktopToScreen(matrix, &rect); + } } } else damageIdx = 0; + if (damageIdx > 0) + damageIdx = egl_clipSurfaceDamage( + damage, damageIdx, this->width, this->height); + this->hadOverlay = hasOverlay; this->cursorLast = cursorState;