diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index dd214bc3..1c4a2e64 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -459,6 +459,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, LG_RendererFrameToken damageFrameToken, LG_RendererFrameToken frameTokenLimit, bool * fullFrame, LG_RendererFrameToken * consumedFrameToken, + LG_RendererFrameToken * renderedFrameToken, uint64_t * effectsTime, EGL_Framebuffer * target) { EGL_Texture * tex; @@ -489,6 +490,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, const bool textureUpdated = status == EGL_TEX_STATUS_UPDATED; *consumedFrameToken = frameToken; + *renderedFrameToken = LG_RENDERER_FRAME_TOKEN_NONE; *effectsTime = 0; if (unlikely(status != EGL_TEX_STATUS_OK && !textureUpdated)) { @@ -567,7 +569,14 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, egl_resetViewport(desktop->egl); } - egl_textureBind(texture); + const EGL_TexStatus bindStatus = egl_textureBind(texture); + if (unlikely(bindStatus != EGL_TEX_STATUS_OK)) + { + if (bindStatus != EGL_TEX_STATUS_NOTREADY) + DEBUG_ERROR("Failed to bind the desktop texture"); + return false; + } + *renderedFrameToken = tex->frameToken; if (finalSizeX > width || finalSizeY > height) scaleType = EGL_DESKTOP_DOWNSCALE; diff --git a/client/renderers/EGL/desktop.h b/client/renderers/EGL/desktop.h index 093b7c17..56944431 100644 --- a/client/renderers/EGL/desktop.h +++ b/client/renderers/EGL/desktop.h @@ -60,6 +60,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, LG_RendererFrameToken damageFrameToken, LG_RendererFrameToken frameTokenLimit, bool * fullFrame, LG_RendererFrameToken * consumedFrameToken, + LG_RendererFrameToken * renderedFrameToken, uint64_t * effectsTime, EGL_Framebuffer * target); void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height); diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 43eda728..2d8e7252 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -1300,6 +1300,31 @@ static int egl_mergeSurfaceDamage(struct Rect * damage, int count) return count; } +static void egl_requeueDesktopDamage( + struct Inst * this, const struct DesktopDamage * damage) +{ + if (damage->count == 0) + return; + + INTERLOCKED_SECTION(this->desktopDamageLock, { + struct DesktopDamage * pending = + this->desktopDamage + this->desktopDamageIdx; + + if (damage->count < 0 || pending->count < 0 || + damage->count + pending->count >= LG_MAX_FRAME_DAMAGE_RECTS) + pending->count = -1; + else + { + memcpy(pending->rects + pending->count, damage->rects, + damage->count * sizeof(FrameDamageRect)); + pending->count += damage->count; + } + + if (pending->frameToken == LG_RENDERER_FRAME_TOKEN_NONE) + pending->frameToken = damage->frameToken; + }); +} + inline static void renderLetterBox(struct Inst * this) { bool hLB = this->destRect.x > 0; @@ -1461,10 +1486,11 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, bool deferredLogicalCursor = false; const bool haveDesktop = likely( this->destRect.w > 0 && this->destRect.h > 0); - bool desktopRendered = false; - const uint64_t desktopStart = nanotime(); - uint64_t effectsTime = 0; - LG_RendererFrameToken frameToken = LG_RENDERER_FRAME_TOKEN_NONE; + bool desktopRendered = false; + const uint64_t desktopStart = nanotime(); + uint64_t effectsTime = 0; + LG_RendererFrameToken frameToken = LG_RENDERER_FRAME_TOKEN_NONE; + LG_RendererFrameToken renderedFrameToken = LG_RENDERER_FRAME_TOKEN_NONE; timing->setupTime = desktopStart - setupStart; if (haveDesktop) @@ -1474,8 +1500,8 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, this->translateX, this->translateY, this->scaleX , this->scaleY , this->scaleType , rotate, renderAll ? NULL : accumulated, - desktopDamage->frameToken, frameTokenLimit, &fullFrame, &frameToken, - &effectsTime, + desktopDamage->frameToken, frameTokenLimit, &fullFrame, + &frameToken, &renderedFrameToken, &effectsTime, egl_hdrComposeGetFramebuffer(this->hdrCompose)); } const uint64_t composeStart = nanotime(); @@ -1489,8 +1515,10 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, else timing->setupTime += composeStart - desktopStart; - timing->frameToken = frameToken; - const bool frameConsumed = frameToken != LG_RENDERER_FRAME_TOKEN_NONE; + const bool frameConsumed = desktopRendered && + frameToken != LG_RENDERER_FRAME_TOKEN_NONE; + timing->frameToken = frameConsumed ? + frameToken : LG_RENDERER_FRAME_TOKEN_NONE; if (haveDesktop) { @@ -1510,6 +1538,18 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate, if (fullFrame) desktopDamage->count = -1; + /* A texture slot can be published before its matching damage and timing + * record. If this render could not consume that slot, retain the damage so + * it is merged into the next drawable frame instead of retiring it. */ + const bool damageRendered = desktopRendered && + (desktopDamage->frameToken == LG_RENDERER_FRAME_TOKEN_NONE || + desktopDamage->frameToken == renderedFrameToken || + ((renderAll || fullFrame) && + renderedFrameToken != LG_RENDERER_FRAME_TOKEN_NONE && + renderedFrameToken > desktopDamage->frameToken)); + if (!damageRendered) + egl_requeueDesktopDamage(this, desktopDamage); + renderLetterBox(this); hasOverlay |=