Files
UnrealEngineUWP/Engine/Source/Runtime/TimeManagement/Private/GenlockedFixedRateCustomTimeStep.cpp
Alejandro Arango 68eede4b10 CustomTimeStep: Added more options to GenlockedCustomTimestep.
* Option to disabling blocking. This is useful when nDisplay is already controlling frame rate. If frame rate is not enforced in some other way, game time will seem to pass at the wrong rate.
* Force single frame delta time. Normally this custom timestemp quantizes the delta time to a whole number that keeps up with real time. With this option, delta time will always be equal to one frame time, regardless to hom much real time has passed.

Defaults leave old behavior unchanged.

#jira
#rb
#preflight 6305d8bc516bef57ffe28566

[CL 21536704 by Alejandro Arango in ue5-main branch]
2022-08-24 04:01:24 -04:00

127 lines
3.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "GenlockedFixedRateCustomTimeStep.h"
#include "Misc/App.h"
UGenlockedFixedRateCustomTimeStep::UGenlockedFixedRateCustomTimeStep(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, FrameRate(24,1)
, bShouldBlock(true)
, bForceSingleFrameDeltaTime(false)
, LastSyncCountDelta(0)
, QuantizedCurrentTime(0.0)
{
}
bool UGenlockedFixedRateCustomTimeStep::Initialize(UEngine* InEngine)
{
return true;
}
void UGenlockedFixedRateCustomTimeStep::Shutdown(UEngine* InEngine)
{
// Empty but implemented because it is PURE_VIRTUAL
}
bool UGenlockedFixedRateCustomTimeStep::UpdateTimeStep(UEngine* InEngine)
{
UpdateApplicationLastTime(); // Copies "CurrentTime" (used during the previous frame) in "LastTime"
WaitForSync();
UpdateAppTimes(QuantizedCurrentTime-LastIdleTime, QuantizedCurrentTime);
return false; // false means that the Engine's TimeStep should NOT be performed.
}
ECustomTimeStepSynchronizationState UGenlockedFixedRateCustomTimeStep::GetSynchronizationState() const
{
return ECustomTimeStepSynchronizationState::Synchronized;
}
FFrameRate UGenlockedFixedRateCustomTimeStep::GetFixedFrameRate() const
{
return FrameRate;
}
uint32 UGenlockedFixedRateCustomTimeStep::GetLastSyncCountDelta() const
{
return LastSyncCountDelta;
}
bool UGenlockedFixedRateCustomTimeStep::IsLastSyncDataValid() const
{
return true;
}
bool UGenlockedFixedRateCustomTimeStep::WaitForSync()
{
const double FramePeriod = GetFixedFrameRate().AsInterval();
double CurrentPlatformTime = FPlatformTime::Seconds();
double DeltaRealTime = CurrentPlatformTime - FApp::GetLastTime();
// Handle the unexpected case of a negative DeltaRealTime by forcing LastTime to CurrentPlatformTime.
if (DeltaRealTime < 0)
{
FApp::SetCurrentTime(CurrentPlatformTime); // Necessary since we don't have direct access to FApp's LastTime
FApp::UpdateLastTime();
DeltaRealTime = CurrentPlatformTime - FApp::GetLastTime(); // DeltaRealTime should be zero now, which will force a sleep
}
checkSlow(DeltaRealTime >= 0);
LastIdleTime = FramePeriod - DeltaRealTime;
if (bShouldBlock)
{
// Sleep during the idle time
if (LastIdleTime > 0.f)
{
// Normal sleep for the bulk of the idle time.
if (LastIdleTime > 5.f / 1000.f)
{
FPlatformProcess::SleepNoStats(LastIdleTime - 0.002f);
}
// Give up timeslice for small remainder of wait time.
const double WaitEndTime = FApp::GetLastTime() + FramePeriod;
while (FPlatformTime::Seconds() < WaitEndTime)
{
FPlatformProcess::SleepNoStats(0.f);
}
// Current platform time should now be right after the desired WaitEndTime, with an overshoot
CurrentPlatformTime = FPlatformTime::Seconds();
FApp::SetIdleTimeOvershoot(CurrentPlatformTime - WaitEndTime);
// Update DeltaRealTime now that we've slept enough
DeltaRealTime = CurrentPlatformTime - FApp::GetLastTime();
}
}
// This +1e-4 avoids a case of LastSyncCountData incorrectly ending up as 0.
DeltaRealTime += 1e-4;
// Quantize elapsed frames, capped to the maximum that the integer type can hold.
LastSyncCountDelta = uint32(FMath::Min(FMath::Floor(DeltaRealTime / FramePeriod), double(MAX_uint32)));
if (bShouldBlock)
{
ensure(LastSyncCountDelta > 0);
}
else if (LastSyncCountDelta < 1)
{
LastSyncCountDelta = 1;
}
if (bForceSingleFrameDeltaTime)
{
LastSyncCountDelta = 1;
}
// Save quantized current time for use outside this function.
QuantizedCurrentTime = FApp::GetLastTime() + LastSyncCountDelta * FramePeriod;
return true;
}