[client] opengl: retain deferred frame leases

This commit is contained in:
Geoffrey McRae
2026-08-24 13:10:36 +10:00
parent 6579fe9098
commit 50b7ca603a
2 changed files with 58 additions and 11 deletions

View File

@@ -100,6 +100,13 @@ struct OpenGL_Options
bool amdPinnedMem; bool amdPinnedMem;
}; };
struct OpenGL_FrameRelease
{
LG_FrameReleaseFn fn;
void * opaque;
uint64_t handle;
};
struct Inst struct Inst
{ {
LG_Renderer base; LG_Renderer base;
@@ -127,6 +134,7 @@ struct Inst
float scaleX, scaleY; float scaleX, scaleY;
const FrameBuffer * frame; const FrameBuffer * frame;
LG_RendererFrameToken pendingFrameToken; LG_RendererFrameToken pendingFrameToken;
struct OpenGL_FrameRelease frameRelease;
uint64_t drawStart; uint64_t drawStart;
bool hasBuffers; bool hasBuffers;
@@ -179,6 +187,7 @@ enum ConfigStatus
static void deconfigure(struct Inst * this); static void deconfigure(struct Inst * this);
static enum ConfigStatus configure(struct Inst * this); static enum ConfigStatus configure(struct Inst * this);
static void releasePendingFrame(struct Inst * this);
static void updateMouseShape(struct Inst * this); static void updateMouseShape(struct Inst * this);
static bool drawFrame(struct Inst * this, static bool drawFrame(struct Inst * this,
LG_RendererFrameToken frameTokenLimit, LG_RendererFrameToken frameTokenLimit,
@@ -203,6 +212,33 @@ static bool swSurfaceEnsureBuffer(struct Inst * this, size_t size)
return true; return true;
} }
static struct OpenGL_FrameRelease takePendingFrameLocked(struct Inst * this)
{
const struct OpenGL_FrameRelease release = this->frameRelease;
this->frame = NULL;
this->pendingFrameToken = LG_RENDERER_FRAME_TOKEN_NONE;
this->frameRelease = (struct OpenGL_FrameRelease) {};
atomic_store_explicit(&this->frameUpdate, false, memory_order_release);
return release;
}
static void invokeFrameRelease(const struct OpenGL_FrameRelease release)
{
if (release.fn)
release.fn(release.opaque, release.handle);
}
static void releasePendingFrame(struct Inst * this)
{
LG_LOCK(this->frameLock);
const struct OpenGL_FrameRelease release =
takePendingFrameLocked(this);
LG_UNLOCK(this->frameLock);
invokeFrameRelease(release);
}
const char * opengl_getName(void) const char * opengl_getName(void)
{ {
return "OpenGL"; return "OpenGL";
@@ -252,6 +288,8 @@ void opengl_deinitialize(LG_Renderer * renderer)
{ {
struct Inst * this = UPCAST(struct Inst, renderer); struct Inst * this = UPCAST(struct Inst, renderer);
releasePendingFrame(this);
if (this->renderStarted) if (this->renderStarted)
{ {
ImGui_ImplOpenGL2_Shutdown(); ImGui_ImplOpenGL2_Shutdown();
@@ -290,7 +328,8 @@ void opengl_deinitialize(LG_Renderer * renderer)
void opengl_onRestart(LG_Renderer * renderer) void opengl_onRestart(LG_Renderer * renderer)
{ {
// struct Inst * this = UPCAST(struct Inst, renderer); struct Inst * this = UPCAST(struct Inst, renderer);
releasePendingFrame(this);
} }
static void setupModelView(struct Inst * this) static void setupModelView(struct Inst * this)
@@ -449,20 +488,25 @@ bool opengl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int dmaFd
{ {
struct Inst * this = UPCAST(struct Inst, renderer); struct Inst * this = UPCAST(struct Inst, renderer);
/* The legacy renderer retains the shared framebuffer until render. It does /* The legacy renderer supports only deferred CPU reads. */
* not support asynchronous DMA ownership. */ if (!frame || dmaFd >= 0)
if (releaseFn)
return false; return false;
(void)releaseOpaque;
(void)releaseHandle;
LG_LOCK(this->frameLock); LG_LOCK(this->frameLock);
const struct OpenGL_FrameRelease oldRelease =
takePendingFrameLocked(this);
this->frame = frame; this->frame = frame;
this->pendingFrameToken = frameToken; this->pendingFrameToken = frameToken;
this->frameRelease = (struct OpenGL_FrameRelease)
{
.fn = releaseFn,
.opaque = releaseOpaque,
.handle = releaseHandle,
};
atomic_store_explicit(&this->frameUpdate, true, memory_order_release); atomic_store_explicit(&this->frameUpdate, true, memory_order_release);
LG_UNLOCK(this->frameLock); LG_UNLOCK(this->frameLock);
invokeFrameRelease(oldRelease);
return true; return true;
} }
@@ -1327,8 +1371,10 @@ static bool drawFrame(struct Inst * this,
LG_UNLOCK(this->frameLock); LG_UNLOCK(this->frameLock);
return true; return true;
} }
atomic_store_explicit(&this->frameUpdate, false, memory_order_release); const FrameBuffer * frame = this->frame;
const LG_RendererFrameToken pendingFrameToken = this->pendingFrameToken; const LG_RendererFrameToken pendingFrameToken = this->pendingFrameToken;
const struct OpenGL_FrameRelease release =
takePendingFrameLocked(this);
LG_LOCK(this->formatLock); LG_LOCK(this->formatLock);
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]); glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
@@ -1340,7 +1386,7 @@ static bool drawFrame(struct Inst * this,
this->texPos = 0; this->texPos = 0;
framebuffer_read_fn( framebuffer_read_fn(
this->frame, frame,
this->format.dataHeight, this->format.dataHeight,
this->format.dataWidth, this->format.dataWidth,
bpp, bpp,
@@ -1406,6 +1452,7 @@ static bool drawFrame(struct Inst * this,
glFlush(); glFlush();
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);
invokeFrameRelease(release);
this->texReady = true; this->texReady = true;
return true; return true;
} }

View File

@@ -1622,7 +1622,7 @@ int main_frameThread(void * unused)
g_state.frameImportTime = 0; g_state.frameImportTime = 0;
g_state.frameImportWaitTime = 0; g_state.frameImportWaitTime = 0;
const bool rendererOwnsFrame = frame.dmaFD >= 0 && frame.releaseFn; const bool rendererOwnsFrame = frame.releaseFn != NULL;
if (!RENDERER(onFrame, frame.framebuffer, frame.dmaFD, if (!RENDERER(onFrame, frame.framebuffer, frame.dmaFD,
frame.damageRects, damageCount, frameToken, frame.damageRects, damageCount, frameToken,
rendererOwnsFrame ? frame.releaseFn : NULL, rendererOwnsFrame ? frame.releaseFn : NULL,
@@ -1638,7 +1638,7 @@ int main_frameThread(void * unused)
primaryWorkerFailed(); primaryWorkerFailed();
break; break;
} }
/* A DMA snapshot can complete on the render thread immediately after it /* A leased frame can complete on the render thread immediately after it
* is signalled below, so sample producer timing while this lease is still * is signalled below, so sample producer timing while this lease is still
* unambiguously owned by the frame thread. */ * unambiguously owned by the frame thread. */
LG_TransportFrameTiming timing = {}; LG_TransportFrameTiming timing = {};