[client] scheduler: release ownership without live cadence

Renew the frame-schedule lease only while the display server is
producing real cadence callbacks. Release ownership after the cadence
stalls, and reacquire with an immediate reset when it resumes.

For non-JIT rendering, treat only a successful presentation as live
cadence.
This commit is contained in:
Geoffrey McRae
2026-08-06 16:37:19 +10:00
parent 3d1064001d
commit 903a8efe75
3 changed files with 24 additions and 8 deletions

View File

@@ -47,7 +47,7 @@ static struct
_Atomic(uint32_t) generation;
_Atomic(uint64_t) period;
uint64_t lastSend;
uint64_t lastCadence;
_Atomic(uint64_t) lastCadence;
int64_t phaseError;
uint32_t feedbackFrameSerial;
@@ -181,19 +181,24 @@ void frameScheduler_stop(void)
l_frameScheduler.immediatePending = false;
}
void frameScheduler_observeCadence(void)
{
atomic_store_explicit(
&l_frameScheduler.lastCadence, nanotime(), memory_order_release);
}
void frameScheduler_update(void)
{
if (!l_frameScheduler.supported)
return;
const uint64_t lastCadence = atomic_load_explicit(
&l_frameScheduler.lastCadence, memory_order_acquire);
const uint64_t now = nanotime();
const uint64_t period = presentationPeriod();
if (period < FRAME_SCHEDULER_MIN_PERIOD_NS ||
period > FRAME_SCHEDULER_MAX_PERIOD_NS)
if (!lastCadence ||
now - lastCadence > FRAME_SCHEDULER_CADENCE_GRACE_NS)
{
if (l_frameScheduler.active && l_frameScheduler.lastCadence &&
now - l_frameScheduler.lastCadence >
FRAME_SCHEDULER_CADENCE_GRACE_NS &&
if (l_frameScheduler.active &&
sendSchedule(LG_TRANSPORT_FRAME_SCHEDULE_RELEASE, 0))
{
l_frameScheduler.active = false;
@@ -210,7 +215,11 @@ void frameScheduler_update(void)
}
return;
}
l_frameScheduler.lastCadence = now;
const uint64_t period = presentationPeriod();
if (period < FRAME_SCHEDULER_MIN_PERIOD_NS ||
period > FRAME_SCHEDULER_MAX_PERIOD_NS)
return;
bool reset = !l_frameScheduler.period;
if (!reset)

View File

@@ -29,6 +29,7 @@ void frameScheduler_init(void);
void frameScheduler_free(void);
void frameScheduler_start(LG_TransportFeatureFlags features);
void frameScheduler_stop(void);
void frameScheduler_observeCadence(void);
void frameScheduler_update(void);
void frameScheduler_feedback(uint64_t frameSerial, uint32_t generation,
uint32_t scheduleEpoch, uint32_t deadlineSerial,

View File

@@ -647,6 +647,9 @@ static int renderThread(void * unused)
if (g_state.jitRender)
{
const LG_DSWaitFrameResult waitResult = g_state.ds->waitFrame();
if (waitResult & LG_DS_WAIT_FRAME_CADENCE)
frameScheduler_observeCadence();
const LG_RendererFrameToken queuedAtWake =
waitResult == LG_DS_WAIT_FRAME_CADENCE ?
frameTimingQueuedToken() : LG_RENDERER_FRAME_TOKEN_NONE;
@@ -756,6 +759,9 @@ static int renderThread(void * unused)
const uint64_t renderEnd = nanotime();
LG_UNLOCK(g_state.lgrLock);
if (!g_state.jitRender)
frameScheduler_observeCadence();
if (rendererTiming.frameToken != LG_RENDERER_FRAME_TOKEN_NONE)
frameTimingFinishRender(
&rendererTiming, prepareStart, prepareTime, renderEnd,