Stage 1 rewrite
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
#include "RenderCadenceController.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
void RenderCadenceController::Configure(Duration targetFrameDuration, TimePoint firstRenderTime, const RenderCadencePolicy& policy)
|
||||
{
|
||||
mTargetFrameDuration = IsPositive(targetFrameDuration) ? targetFrameDuration : std::chrono::milliseconds(1);
|
||||
mPolicy = policy;
|
||||
if (mPolicy.skipThresholdFrames < 1.0)
|
||||
mPolicy.skipThresholdFrames = 1.0;
|
||||
Reset(firstRenderTime);
|
||||
}
|
||||
|
||||
void RenderCadenceController::Reset(TimePoint firstRenderTime)
|
||||
{
|
||||
mNextRenderTime = firstRenderTime;
|
||||
mNextFrameIndex = 0;
|
||||
mMetrics = RenderCadenceMetrics();
|
||||
}
|
||||
|
||||
RenderCadenceDecision RenderCadenceController::Tick(TimePoint now)
|
||||
{
|
||||
RenderCadenceDecision decision;
|
||||
decision.frameIndex = mNextFrameIndex;
|
||||
decision.renderTargetTime = mNextRenderTime;
|
||||
decision.nextRenderTime = mNextRenderTime;
|
||||
|
||||
if (now < mNextRenderTime)
|
||||
{
|
||||
decision.action = RenderCadenceAction::Wait;
|
||||
decision.waitDuration = mNextRenderTime - now;
|
||||
decision.reason = "waiting-for-next-render-tick";
|
||||
return decision;
|
||||
}
|
||||
|
||||
const Duration lateness = now - mNextRenderTime;
|
||||
const uint64_t skippedTicks = SkippedTicksForLateness(lateness);
|
||||
if (skippedTicks > 0)
|
||||
{
|
||||
decision.skippedTicks = skippedTicks;
|
||||
decision.frameIndex = mNextFrameIndex + skippedTicks;
|
||||
decision.renderTargetTime = mNextRenderTime + (mTargetFrameDuration * skippedTicks);
|
||||
decision.reason = "late-skip-render-ticks";
|
||||
mMetrics.skippedTickCount += skippedTicks;
|
||||
}
|
||||
else
|
||||
{
|
||||
decision.reason = IsPositive(lateness) ? "late-render-now" : "on-time-render";
|
||||
}
|
||||
|
||||
decision.action = RenderCadenceAction::Render;
|
||||
decision.lateness = now > decision.renderTargetTime
|
||||
? now - decision.renderTargetTime
|
||||
: Duration::zero();
|
||||
mNextFrameIndex = decision.frameIndex + 1;
|
||||
mNextRenderTime = decision.renderTargetTime + mTargetFrameDuration;
|
||||
decision.nextRenderTime = mNextRenderTime;
|
||||
|
||||
++mMetrics.renderedFrameCount;
|
||||
mMetrics.nextFrameIndex = mNextFrameIndex;
|
||||
mMetrics.lastLateness = decision.lateness;
|
||||
if (IsPositive(decision.lateness))
|
||||
{
|
||||
++mMetrics.lateFrameCount;
|
||||
mMetrics.maxLateness = (std::max)(mMetrics.maxLateness, decision.lateness);
|
||||
}
|
||||
|
||||
return decision;
|
||||
}
|
||||
|
||||
uint64_t RenderCadenceController::SkippedTicksForLateness(Duration lateness) const
|
||||
{
|
||||
if (!mPolicy.skipLateTicks || !IsPositive(lateness) || !IsPositive(mTargetFrameDuration))
|
||||
return 0;
|
||||
|
||||
const double lateFrames = static_cast<double>(lateness.count()) / static_cast<double>(mTargetFrameDuration.count());
|
||||
if (lateFrames < mPolicy.skipThresholdFrames)
|
||||
return 0;
|
||||
|
||||
const uint64_t elapsedTicks = static_cast<uint64_t>(std::floor(lateFrames));
|
||||
if (elapsedTicks == 0)
|
||||
return 0;
|
||||
return (std::min)(elapsedTicks, mPolicy.maxSkippedTicksPerDecision);
|
||||
}
|
||||
|
||||
bool RenderCadenceController::IsPositive(Duration duration)
|
||||
{
|
||||
return duration > Duration::zero();
|
||||
}
|
||||
|
||||
const char* RenderCadenceActionName(RenderCadenceAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case RenderCadenceAction::Render:
|
||||
return "Render";
|
||||
case RenderCadenceAction::Wait:
|
||||
default:
|
||||
return "Wait";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user