Frame timing
All checks were successful
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m53s
CI / Windows Release Package (push) Successful in 3m6s

This commit is contained in:
Aiden
2026-05-12 01:08:32 +10:00
parent ac729dc2b9
commit f1f4e3421b
6 changed files with 141 additions and 39 deletions

View File

@@ -47,6 +47,18 @@ bool RenderOutputQueue::TryPop(RenderOutputFrame& frame)
return true;
}
bool RenderOutputQueue::DropOldestFrame()
{
std::lock_guard<std::mutex> lock(mMutex);
if (mReadyFrames.empty())
return false;
ReleaseFrame(mReadyFrames.front());
mReadyFrames.pop_front();
++mDroppedCount;
return true;
}
void RenderOutputQueue::Clear()
{
std::lock_guard<std::mutex> lock(mMutex);

View File

@@ -34,6 +34,7 @@ public:
void Configure(const VideoPlayoutPolicy& policy);
bool Push(RenderOutputFrame frame);
bool TryPop(RenderOutputFrame& frame);
bool DropOldestFrame();
void Clear();
RenderOutputQueueMetrics GetMetrics() const;

View File

@@ -359,6 +359,12 @@ void VideoBackend::StartOutputProducerWorker()
if (mOutputProducerWorkerRunning)
return;
const double frameBudgetMilliseconds = State().frameBudgetMilliseconds;
const auto frameDuration = frameBudgetMilliseconds > 0.0
? std::chrono::duration_cast<RenderCadenceController::Duration>(
std::chrono::duration<double, std::milli>(frameBudgetMilliseconds))
: std::chrono::milliseconds(16);
mRenderCadenceController.Configure(frameDuration, std::chrono::steady_clock::now());
mLastOutputProductionCompletion = VideoIOCompletion();
mLastOutputProductionTime = std::chrono::steady_clock::time_point();
mOutputProducerWorkerStopping = false;
@@ -433,11 +439,16 @@ void VideoBackend::OutputProducerWorkerMain()
const RenderOutputQueueMetrics metrics = mReadyOutputQueue.GetMetrics();
RecordReadyQueueDepthSample(metrics);
const OutputProductionDecision decision = mOutputProductionController.Decide(BuildOutputProductionPressure(metrics));
if (decision.action != OutputProductionAction::Produce || decision.requestedFrames == 0)
const auto now = std::chrono::steady_clock::now();
RenderCadenceDecision cadenceDecision = mRenderCadenceController.Tick(now);
if (cadenceDecision.action == RenderCadenceAction::Wait)
{
const auto waitDuration = (std::min)(
std::chrono::duration_cast<std::chrono::milliseconds>(cadenceDecision.waitDuration),
OutputProducerWakeInterval());
std::unique_lock<std::mutex> lock(mOutputProducerMutex);
mOutputProducerCondition.wait_for(lock, OutputProducerWakeInterval());
mOutputProducerCondition.wait_for(lock, waitDuration);
if (mOutputProducerWorkerStopping)
{
mOutputProducerWorkerRunning = false;
@@ -454,16 +465,7 @@ void VideoBackend::OutputProducerWorkerMain()
completion = mLastOutputProductionCompletion;
}
const bool belowTargetDepth = metrics.depth < decision.targetReadyFrames;
const auto now = std::chrono::steady_clock::now();
if (!belowTargetDepth &&
mLastOutputProductionTime != std::chrono::steady_clock::time_point() &&
now - mLastOutputProductionTime < OutputProducerWakeInterval())
{
continue;
}
const std::size_t producedFrames = ProduceReadyOutputFrames(completion, decision.requestedFrames);
const std::size_t producedFrames = ProduceReadyOutputFrames(completion, 1);
if (producedFrames > 0)
{
mLastOutputProductionTime = std::chrono::steady_clock::now();
@@ -600,10 +602,6 @@ std::size_t VideoBackend::ProduceReadyOutputFrames(const VideoIOCompletion& comp
std::size_t producedFrames = 0;
while (producedFrames < maxFrames)
{
const OutputProductionDecision decision = mOutputProductionController.Decide(BuildOutputProductionPressure(metrics));
if (decision.action != OutputProductionAction::Produce)
break;
if (!RenderReadyOutputFrame(mVideoIODevice->State(), completion))
break;
++producedFrames;
@@ -634,7 +632,10 @@ bool VideoBackend::RenderReadyOutputFrame(const VideoIOState& state, const Video
VideoIOOutputFrame outputFrame;
const auto acquireStart = std::chrono::steady_clock::now();
if (!mSystemOutputFramePool.AcquireFreeSlot(outputSlot))
return false;
{
if (!mReadyOutputQueue.DropOldestFrame() || !mSystemOutputFramePool.AcquireFreeSlot(outputSlot))
return false;
}
outputFrame = outputSlot.frame;
const auto acquireEnd = std::chrono::steady_clock::now();

View File

@@ -1,6 +1,7 @@
#pragma once
#include "OutputProductionController.h"
#include "RenderCadenceController.h"
#include "RenderOutputQueue.h"
#include "SystemOutputFramePool.h"
#include "VideoBackendLifecycle.h"
@@ -105,6 +106,7 @@ private:
VideoBackendLifecycle mLifecycle;
VideoPlayoutPolicy mPlayoutPolicy;
OutputProductionController mOutputProductionController;
RenderCadenceController mRenderCadenceController;
RenderOutputQueue mReadyOutputQueue;
SystemOutputFramePool mSystemOutputFramePool;
std::unique_ptr<VideoIODevice> mVideoIODevice;