From b9a7ce17fe32a9d632421822f979fb4edb04110c Mon Sep 17 00:00:00 2001 From: Quantum Date: Sat, 31 Jul 2021 20:37:23 -0400 Subject: [PATCH] [client] egl: use queue of damages This prevents damage from being overwritten when frames are received faster than could be rendered. This implementation cycles between two queues, removing all need for memory allocation. --- client/renderers/EGL/egl.c | 86 +++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 11f1fc01..128120e3 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -49,6 +49,7 @@ #include "splash.h" #define SPLASH_FADE_TIME 1000000 +#define DESKTOP_DAMAGE_COUNT 2 struct Options { @@ -101,8 +102,9 @@ struct Inst struct CursorState cursorLast; - bool hadOverlay; - _Atomic(struct DesktopDamage *) desktopDamage; + bool hadOverlay; + struct DesktopDamage desktopDamage[DESKTOP_DAMAGE_COUNT]; + atomic_uint desktopDamageIdx; RingBuffer importTimings; GraphHandle importGraph; @@ -180,6 +182,16 @@ static void egl_setup(void) option_register(egl_options); } +inline static struct DesktopDamage * currentDesktopDamage(struct Inst * this) +{ + return this->desktopDamage + atomic_load(&this->desktopDamageIdx) % DESKTOP_DAMAGE_COUNT; +} + +inline static struct DesktopDamage * finishDesktopDamage(struct Inst * this) +{ + return this->desktopDamage + atomic_fetch_add(&this->desktopDamageIdx, 1) % DESKTOP_DAMAGE_COUNT; +} + static bool egl_create(void ** opaque, const LG_RendererParams params, bool * needsOpenGL) { // check if EGL is even available @@ -209,7 +221,8 @@ static bool egl_create(void ** opaque, const LG_RendererParams params, bool * ne this->screenScaleY = 1.0f; this->uiScale = 1.0; - atomic_init(&this->desktopDamage, NULL); + atomic_init(&this->desktopDamageIdx, 0); + this->desktopDamage[0].count = -1; this->importTimings = ringbuffer_new(256, sizeof(float)); this->importGraph = app_registerGraph("IMPORT", this->importTimings, 0.0f, 5.0f); @@ -419,14 +432,7 @@ static void egl_on_resize(void * opaque, const int width, const int height, cons egl_calc_mouse_state(this); - struct DesktopDamage * damage = malloc(sizeof(struct DesktopDamage)); - if (!damage) - { - DEBUG_FATAL("Out of memory"); - abort(); - } - damage->count = 0; - free(atomic_exchange(&this->desktopDamage, damage)); + currentDesktopDamage(this)->count = -1; // this is needed to refresh the font atlas texture ImGui_ImplOpenGL3_Shutdown(); @@ -512,15 +518,14 @@ static bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd, this->start = true; - struct DesktopDamage * damage = malloc(sizeof(struct DesktopDamage)); - if (!damage) + struct DesktopDamage * damage = currentDesktopDamage(this); + if (damage->count == -1 || damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS) + damage->count = -1; + else { - DEBUG_FATAL("Out of memory"); - abort(); + memcpy(damage->rects + damage->count, damageRects, damageRectsCount * sizeof(FrameDamageRect)); + damage->count += damageRectsCount; } - damage->count = damageRectsCount; - memcpy(damage->rects, damageRects, damageRectsCount * sizeof(FrameDamageRect)); - free(atomic_exchange(&this->desktopDamage, damage)); return true; } @@ -810,11 +815,10 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr bool hasOverlay = false; struct CursorState cursorState = { .visible = false }; - struct DesktopDamage * desktopDamage = NULL; + struct DesktopDamage * desktopDamage = finishDesktopDamage(this); if (this->start) { - desktopDamage = atomic_exchange(&this->desktopDamage, NULL); if (egl_desktop_render(this->desktop, this->translateX, this->translateY, this->scaleX , this->scaleY , @@ -833,7 +837,7 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr this->width, this->height); } else - desktopDamage->count = 0; + desktopDamage->count = -1; } if (!this->waitDone) @@ -865,7 +869,7 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr hasOverlay = true; } - if (desktopDamage && rotate != LG_ROTATE_0) + if (desktopDamage->count > 0 && rotate != LG_ROTATE_0) { for (int i = 0; i < desktopDamage->count; ++i) { @@ -958,34 +962,32 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr this->cursorLast = cursorState; - if (desktopDamage) + if (desktopDamage->count == -1) + // -1 damage count means invalidating entire window. + damageIdx = 0; + else { - if (desktopDamage->count == 0) - // Zero damage count means invalidating entire window. - damageIdx = 0; - else + for (int i = 0; i < desktopDamage->count; ++i) { - for (int i = 0; i < desktopDamage->count; ++i) - { - FrameDamageRect rect = desktopDamage->rects[i]; - int x1 = (int) (rect.x * scaleX); - int y1 = (int) (rect.y * scaleY); - int x2 = (int) ceil((rect.x + rect.width) * scaleX); - int y2 = (int) ceil((rect.y + rect.height) * scaleY); - damage[damageIdx++] = (struct Rect) { - .x = this->destRect.x + x1, - .y = this->height - (this->destRect.y + y2), - .w = x2 - x1, - .h = y2 - y1, - }; - } + FrameDamageRect rect = desktopDamage->rects[i]; + int x1 = (int) (rect.x * scaleX); + int y1 = (int) (rect.y * scaleY); + int x2 = (int) ceil((rect.x + rect.width) * scaleX); + int y2 = (int) ceil((rect.y + rect.height) * scaleY); + damage[damageIdx++] = (struct Rect) { + .x = this->destRect.x + x1, + .y = this->height - (this->destRect.y + y2), + .w = x2 - x1, + .h = y2 - y1, + }; } } } else damageIdx = 0; + this->hadOverlay = hasOverlay; - free(desktopDamage); + desktopDamage->count = 0; app_eglSwapBuffers(this->display, this->surface, damage, damageIdx); return true;