mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[client] scheduler: qualify presentation feedback
Track cadence, interruption, and calibration wake reasons independently across X11 and Wayland. Feed phase correction back only when a pure cadence wake renders the exact frame that was queued at that wake. Propagate EGL swap results through the display-server boundary. Reject failed presentations and keep pending Wayland HDR descriptions inactive until the preceding surface commit succeeds.
This commit is contained in:
@@ -838,9 +838,10 @@ EGLNativeWindowType app_getEGLNativeWindow(void)
|
||||
return g_state.ds->getEGLNativeWindow();
|
||||
}
|
||||
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
||||
bool app_eglSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||
const struct Rect * damage, int count)
|
||||
{
|
||||
g_state.ds->eglSwapBuffers(display, surface, damage, count);
|
||||
return g_state.ds->eglSwapBuffers(display, surface, damage, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -52,14 +52,11 @@ void swapWithDamageDisable(struct SwapWithDamageData * data)
|
||||
data->func = NULL;
|
||||
}
|
||||
|
||||
void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSurface surface,
|
||||
const struct Rect * damage, int count)
|
||||
bool swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display,
|
||||
EGLSurface surface, const struct Rect * damage, int count)
|
||||
{
|
||||
if (!data->func || !count)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
return;
|
||||
}
|
||||
return eglSwapBuffers(display, surface) == EGL_TRUE;
|
||||
|
||||
EGLint rects[count * 4];
|
||||
for (int i = 0; i < count; ++i)
|
||||
@@ -69,5 +66,5 @@ void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSur
|
||||
rects[i * 4 + 2] = damage[i].w;
|
||||
rects[i * 4 + 3] = damage[i].h;
|
||||
}
|
||||
data->func(display, surface, rects, count);
|
||||
return data->func(display, surface, rects, count) == EGL_TRUE;
|
||||
}
|
||||
|
||||
@@ -394,7 +394,8 @@ static void frameTimingFinishFrame(LG_RendererFrameToken token,
|
||||
}
|
||||
|
||||
static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
||||
uint64_t prepareStart, uint64_t prepareTime, uint64_t timestamp)
|
||||
uint64_t prepareStart, uint64_t prepareTime, uint64_t timestamp,
|
||||
LG_RendererFrameToken cadenceToken)
|
||||
{
|
||||
uint64_t feedbackFrameSerial = 0;
|
||||
uint64_t feedbackQueueStart = 0;
|
||||
@@ -425,7 +426,8 @@ static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
||||
feedbackGeneration = record->scheduleGeneration;
|
||||
feedbackEpoch = record->scheduleEpoch;
|
||||
feedbackDeadline = record->scheduleDeadlineSerial;
|
||||
feedbackValid = record->phaseValid;
|
||||
feedbackValid = record->phaseValid &&
|
||||
timing->frameToken == cadenceToken;
|
||||
feedbackQueueStart = record->queueStart;
|
||||
|
||||
if (unlikely(
|
||||
@@ -640,9 +642,16 @@ static int renderThread(void * unused)
|
||||
|
||||
while(likely(app_getState() != APP_STATE_SHUTDOWN))
|
||||
{
|
||||
LG_RendererFrameToken cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||
|
||||
if (g_state.jitRender)
|
||||
{
|
||||
const bool forceRender = g_state.ds->waitFrame();
|
||||
const LG_DSWaitFrameResult waitResult = g_state.ds->waitFrame();
|
||||
const LG_RendererFrameToken queuedAtWake =
|
||||
waitResult == LG_DS_WAIT_FRAME_CADENCE ?
|
||||
frameTimingQueuedToken() : LG_RENDERER_FRAME_TOKEN_NONE;
|
||||
const bool forceRender =
|
||||
waitResult & LG_DS_WAIT_FRAME_FORCE_RENDER;
|
||||
app_handleRenderEvent(microtime());
|
||||
|
||||
const uint64_t pending =
|
||||
@@ -657,11 +666,9 @@ static int renderThread(void * unused)
|
||||
const bool overlayRender = overlayNeeded &&
|
||||
(!g_state.lastRenderTimeValid || !periodKnown ||
|
||||
elapsed + outputPeriod >= g_state.overlayFrameTime);
|
||||
const bool clientWake = lgResetEvent(g_state.frameEvent);
|
||||
|
||||
if (!lgResetEvent(g_state.frameEvent)
|
||||
&& !forceRender
|
||||
&& !pending
|
||||
&& !overlayRender)
|
||||
if (!clientWake && !forceRender && !pending && !overlayRender)
|
||||
{
|
||||
if (g_state.ds->skipFrame)
|
||||
g_state.ds->skipFrame();
|
||||
@@ -669,7 +676,11 @@ static int renderThread(void * unused)
|
||||
}
|
||||
|
||||
if (pending > 0)
|
||||
{
|
||||
atomic_fetch_sub(&g_state.pendingCount, 1);
|
||||
if (!clientWake)
|
||||
cadenceToken = queuedAtWake;
|
||||
}
|
||||
}
|
||||
else if (g_params.fpsMin != 0)
|
||||
{
|
||||
@@ -693,8 +704,10 @@ static int renderThread(void * unused)
|
||||
igGetStyle()->FontScaleMain = 1.0f / g_state.windowScale;
|
||||
}
|
||||
|
||||
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
||||
if (unlikely(fontDirty || g_state.fontScale != g_state.windowScale))
|
||||
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
||||
const bool fontUpdate = fontDirty ||
|
||||
g_state.fontScale != g_state.windowScale;
|
||||
if (unlikely(fontUpdate))
|
||||
{
|
||||
if (!util_buildUIFontAtlas(g_state.io->Fonts,
|
||||
g_params.uiSize * g_state.windowScale, &g_state.fontLarge))
|
||||
@@ -706,6 +719,9 @@ static int renderThread(void * unused)
|
||||
g_state.fontScale = g_state.windowScale;
|
||||
}
|
||||
|
||||
if (unlikely(resize || fontUpdate))
|
||||
cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||
|
||||
if (unlikely(resize))
|
||||
{
|
||||
if (g_state.lgr)
|
||||
@@ -721,11 +737,14 @@ static int renderThread(void * unused)
|
||||
|
||||
renderQueue_process();
|
||||
|
||||
const bool windowInvalid =
|
||||
const bool windowInvalid =
|
||||
atomic_exchange(&g_state.invalidateWindow, false);
|
||||
const bool overlayFull = app_overlayNeedsFullRender();
|
||||
const bool invalidate = windowInvalid || overlayFull;
|
||||
const uint64_t prepareTime = nanotime() - prepareStart;
|
||||
const bool overlayFull = app_overlayNeedsFullRender();
|
||||
const bool invalidate = windowInvalid || overlayFull;
|
||||
const uint64_t prepareTime = nanotime() - prepareStart;
|
||||
|
||||
if (unlikely(invalidate))
|
||||
cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||
|
||||
LG_RendererFrameTiming rendererTiming = {};
|
||||
if (unlikely(!RENDERER(render, g_params.winRotate, frameTokenLimit,
|
||||
@@ -739,7 +758,8 @@ static int renderThread(void * unused)
|
||||
|
||||
if (rendererTiming.frameToken != LG_RENDERER_FRAME_TOKEN_NONE)
|
||||
frameTimingFinishRender(
|
||||
&rendererTiming, prepareStart, prepareTime, renderEnd);
|
||||
&rendererTiming, prepareStart, prepareTime, renderEnd,
|
||||
cadenceToken);
|
||||
frameTimingPublishReady();
|
||||
|
||||
const uint64_t t = nanotime();
|
||||
|
||||
Reference in New Issue
Block a user