diff --git a/client/include/app.h b/client/include/app.h index ddbd202e..a147bb7c 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -80,6 +80,7 @@ void app_glSetSwapInterval(int interval); void app_glSwapBuffers(void); #endif +#define MAX_OVERLAY_RECTS 10 void app_registerOverlay(const struct LG_OverlayOps * ops, void * params); /** diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 5821eb70..fffbae36 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -1007,8 +1007,8 @@ bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFrame) hasOverlay |= egl_help_render(this->help, this->screenScaleX, this->screenScaleY); hasOverlay |= egl_damage_render(this->damage, newFrame ? desktopDamage : NULL); - struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + 12]; - int damageIdx = app_renderOverlay(damage, 10); + struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2]; + int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS); switch (damageIdx) { diff --git a/client/src/app.c b/client/src/app.c index 7a8c9ddb..8c793b8e 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -628,6 +628,8 @@ struct Overlay { const struct LG_OverlayOps * ops; void * udata; + int lastRectCount; + struct Rect lastRects[MAX_OVERLAY_RECTS]; }; void app_registerOverlay(const struct LG_OverlayOps * ops, void * params) @@ -642,16 +644,29 @@ void app_registerOverlay(const struct LG_OverlayOps * ops, void * params) } struct Overlay * overlay = malloc(sizeof(struct Overlay)); - overlay->ops = ops; - overlay->udata = udata; + overlay->ops = ops; + overlay->udata = udata; + overlay->lastRectCount = 0; ll_push(g_state.overlays, overlay); } +static inline void mergeRect(struct Rect * dest, const struct Rect * a, const struct Rect * b) +{ + int x2 = max(a->x + a->w, b->x + b->w); + int y2 = max(a->y + a->h, b->y + b->h); + + dest->x = min(a->x, b->x); + dest->y = min(a->y, b->y); + dest->w = x2 - dest->x; + dest->h = y2 - dest->y; +} + int app_renderOverlay(struct Rect * rects, int maxRects) { int totalRects = 0; bool totalDamage = false; struct Overlay * overlay; + struct Rect buffer[MAX_OVERLAY_RECTS]; igNewFrame(); @@ -660,25 +675,32 @@ int app_renderOverlay(struct Rect * rects, int maxRects) ll_walk(g_state.overlays, (void **)&overlay); ) { const int written = - overlay->ops->render(overlay->udata, false, rects, maxRects); + overlay->ops->render(overlay->udata, false, buffer, MAX_OVERLAY_RECTS); - if (totalDamage) - continue; + // It is an error to run out of rectangles, because we will not be able to + // correctly calculate the damage of the next frame. + assert(written >= 0); - if (written == -1) + const int toAdd = max(written, overlay->lastRectCount); + totalDamage |= toAdd > maxRects; + + if (!totalDamage && toAdd) { - // out of rects, return that the entire surface is damaged - totalDamage = true; - rects = NULL; - maxRects = 0; - totalRects = 0; - } - else - { - maxRects -= written; - rects += written; - totalRects += written; + int i = 0; + for (; i < overlay->lastRectCount && i < written; ++i) + mergeRect(rects + i, buffer + i, overlay->lastRects + i); + + // only one of the following memcpys will copy non-zero bytes. + memcpy(rects + i, buffer + i, (written - i) * sizeof(struct Rect)); + memcpy(rects + i, overlay->lastRects + i, (overlay->lastRectCount - i) * sizeof(struct Rect)); + + rects += toAdd; + totalRects += toAdd; + maxRects -= toAdd; } + + memcpy(overlay->lastRects, buffer, sizeof(struct Rect) * written); + overlay->lastRectCount = written; } igRender();