[client] imgui: track last rectangles for overlays

This is necessary in case overlays change size. When this happens, we must
damage the larger of the overlays' rectangles this frame and last frame.
This erases the overlay from where it is no longer appears.

In order to do this, we must keep track of the rectangles for every overlay
with no exception. We cannot short-circuit the generation of rectangles if
we run out of buffer space, and we must allocate space for MAX_OVERLAY_RECTS
rectangles for every frame. Otherwise, we will not know where to erase the
overlay if it disappears.
This commit is contained in:
Quantum 2021-07-22 05:43:16 -04:00 committed by Geoffrey McRae
parent 334bfeecea
commit df0397b10b
3 changed files with 42 additions and 19 deletions

View file

@ -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);
/**

View file

@ -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)
{

View file

@ -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();