130 lines
3.6 KiB
C++
130 lines
3.6 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "GenlockedFixedRateCustomTimeStep.h"
|
|
#include "Misc/App.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(GenlockedFixedRateCustomTimeStep)
|
|
|
|
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((float)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;
|
|
}
|
|
|