mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[client/obs] scheduler: correct phase feedback
Only report the client queue lead when JIT rendering provides a valid measurement. Clamp linear phase errors instead of wrapping them into the opposite direction at half of a refresh period. Timestamp OBS frames after the shared framebuffer becomes ready.
This commit is contained in:
@@ -262,11 +262,11 @@ void frameScheduler_feedback(uint64_t frameSerial, uint32_t generation,
|
|||||||
int64_t error = measuredPhase > FRAME_SCHEDULER_TARGET_SLACK_NS ?
|
int64_t error = measuredPhase > FRAME_SCHEDULER_TARGET_SLACK_NS ?
|
||||||
(int64_t)(measuredPhase - FRAME_SCHEDULER_TARGET_SLACK_NS) :
|
(int64_t)(measuredPhase - FRAME_SCHEDULER_TARGET_SLACK_NS) :
|
||||||
-(int64_t)(FRAME_SCHEDULER_TARGET_SLACK_NS - measuredPhase);
|
-(int64_t)(FRAME_SCHEDULER_TARGET_SLACK_NS - measuredPhase);
|
||||||
error %= period;
|
const int64_t limit = period / 2;
|
||||||
if (error > period / 2)
|
if (error > limit)
|
||||||
error -= period;
|
error = limit;
|
||||||
else if (error < -period / 2)
|
else if (error < -limit)
|
||||||
error += period;
|
error = -limit;
|
||||||
|
|
||||||
if (!l_frameScheduler.feedbackSamples)
|
if (!l_frameScheduler.feedbackSamples)
|
||||||
l_frameScheduler.phaseError = error;
|
l_frameScheduler.phaseError = error;
|
||||||
|
|||||||
@@ -434,17 +434,12 @@ static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
|||||||
}
|
}
|
||||||
LG_UNLOCK(l_frameTiming.lock);
|
LG_UNLOCK(l_frameTiming.lock);
|
||||||
|
|
||||||
if (feedbackFrameSerial && feedbackGeneration)
|
if (g_state.jitRender && feedbackFrameSerial && feedbackGeneration &&
|
||||||
|
feedbackQueueStart && prepareStart >= feedbackQueueStart)
|
||||||
{
|
{
|
||||||
uint64_t measuredPhase = timing->swapTime;
|
|
||||||
if (g_state.jitRender)
|
|
||||||
{
|
|
||||||
if (!feedbackQueueStart || prepareStart < feedbackQueueStart)
|
|
||||||
return;
|
|
||||||
measuredPhase = prepareStart - feedbackQueueStart;
|
|
||||||
}
|
|
||||||
frameScheduler_feedback(
|
frameScheduler_feedback(
|
||||||
feedbackFrameSerial, feedbackGeneration, measuredPhase);
|
feedbackFrameSerial, feedbackGeneration,
|
||||||
|
prepareStart - feedbackQueueStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,11 +98,11 @@ void lgFrameSchedulerFeedback(LGFrameScheduler * scheduler,
|
|||||||
(int64_t)(measuredPhase - FRAME_SCHEDULER_TARGET_SLACK_NS) :
|
(int64_t)(measuredPhase - FRAME_SCHEDULER_TARGET_SLACK_NS) :
|
||||||
-(int64_t)(FRAME_SCHEDULER_TARGET_SLACK_NS - measuredPhase);
|
-(int64_t)(FRAME_SCHEDULER_TARGET_SLACK_NS - measuredPhase);
|
||||||
const int64_t period = (int64_t)scheduler->period;
|
const int64_t period = (int64_t)scheduler->period;
|
||||||
error %= period;
|
const int64_t limit = period / 2;
|
||||||
if (error > period / 2)
|
if (error > limit)
|
||||||
error -= period;
|
error = limit;
|
||||||
else if (error < -period / 2)
|
else if (error < -limit)
|
||||||
error += period;
|
error = -limit;
|
||||||
|
|
||||||
if (!scheduler->feedbackSamples)
|
if (!scheduler->feedbackSamples)
|
||||||
scheduler->phaseError = error;
|
scheduler->phaseError = error;
|
||||||
|
|||||||
11
obs/lg.c
11
obs/lg.c
@@ -505,17 +505,24 @@ static void * frameThread(void * data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t now = os_gettime_ns();
|
uint64_t now = os_gettime_ns();
|
||||||
if (status == LGMP_OK)
|
if (status == LGMP_OK)
|
||||||
{
|
{
|
||||||
LGMPMessage msg;
|
LGMPMessage msg;
|
||||||
if (lgmpClientProcess(this->frameQueue, &msg) == LGMP_OK)
|
if (lgmpClientProcess(this->frameQueue, &msg) == LGMP_OK)
|
||||||
{
|
{
|
||||||
const KVMFRFrame * frame = (const KVMFRFrame *)msg.mem;
|
const KVMFRFrame * frame = (const KVMFRFrame *)msg.mem;
|
||||||
|
const FrameBuffer * fb =
|
||||||
|
(const FrameBuffer *)((const uint8_t *)frame + frame->offset);
|
||||||
|
if (framebuffer_wait(
|
||||||
|
fb, (size_t)frame->dataHeight * frame->pitch))
|
||||||
|
{
|
||||||
|
now = os_gettime_ns();
|
||||||
lgFrameSchedulerObserveFrame(&this->frameScheduler,
|
lgFrameSchedulerObserveFrame(&this->frameScheduler,
|
||||||
frame->frameSerial, msg.udata, now);
|
frame->frameSerial, msg.udata, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&this->pointerLock);
|
pthread_mutex_lock(&this->pointerLock);
|
||||||
lgFrameSchedulerUpdate(&this->frameScheduler,
|
lgFrameSchedulerUpdate(&this->frameScheduler,
|
||||||
@@ -1287,8 +1294,6 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const KVMFRFrame * frame = (KVMFRFrame *)msg.mem;
|
const KVMFRFrame * frame = (KVMFRFrame *)msg.mem;
|
||||||
lgFrameSchedulerObserveFrame(&this->frameScheduler,
|
|
||||||
frame->frameSerial, msg.udata, tickTime);
|
|
||||||
lgFrameSchedulerFeedback(&this->frameScheduler,
|
lgFrameSchedulerFeedback(&this->frameScheduler,
|
||||||
frame->frameSerial, msg.udata, tickTime);
|
frame->frameSerial, msg.udata, tickTime);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user