// Copyright Epic Games, Inc. All Rights Reserved. #include "Estimation/TimecodeRegressionProvider.h" #include "Engine/Engine.h" #include "Engine/EngineCustomTimeStep.h" #include "Estimation/IClockedTimeStep.h" #include "ITimeManagementModule.h" #include "Misc/App.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(TimecodeRegressionProvider) bool UTimecodeRegressionProvider::SupportsTimestep(UEngineCustomTimeStep* InTimestep) { return InTimestep && InTimestep->Implements(); } void UTimecodeRegressionProvider::SetTimecodeImplementation(UTimecodeProvider* InTimecodeImpl) { if (InTimecodeImpl && ensureMsgf(!IsInitialized(), TEXT("Invalid to call while in use by engine (i.e. Initialize has been called already)"))) { TimecodeImpl = InTimecodeImpl; } } TOptional UTimecodeRegressionProvider::GetLastSampledFrameTime() const { return EstimationState && EstimationState->LastUpdateStats ? EstimationState->LastUpdateStats->UnderlyingFrameTime : TOptional(); } void UTimecodeRegressionProvider::FetchAndUpdate() { if (EstimationState) { EstimationState->LastUpdateStats = EstimationState->TimecodeEstimator.FetchAndUpdate(); } // This is just a sensible fallback if ReinitRegressionBuffer failed due to unsupported timestep class else if (TimecodeImpl) { TimecodeImpl->FetchAndUpdate(); } } FQualifiedFrameTime UTimecodeRegressionProvider::GetQualifiedFrameTime() const { const FQualifiedFrameTime Time = EstimationState ? EstimationState->TimecodeEstimator.EstimateFrameTime() // This is just a sensible fallback if ReinitRegressionBuffer failed due to unsupported timestep class or missing call to SetTimecodeImplementation. : TimecodeImpl ? TimecodeImpl->GetQualifiedFrameTime() : FQualifiedFrameTime(); return Time; } ETimecodeProviderSynchronizationState UTimecodeRegressionProvider::GetSynchronizationState() const { if (!IsInitialized()) { return ETimecodeProviderSynchronizationState::Closed; } // The custom time step can be changed after we've been initialized if (!OwningEngine->GetCustomTimeStep()) { return ETimecodeProviderSynchronizationState::Error; } return TimecodeImpl->GetSynchronizationState(); } bool UTimecodeRegressionProvider::Initialize(UEngine* InEngine) { if (ensureMsgf(TimecodeImpl, TEXT("You forgot to call SetTimecodeImplementation before")) && TimecodeImpl->Initialize(InEngine)) { OwningEngine = InEngine; OwningEngine->OnCustomTimeStepChanged().AddUObject(this, &UTimecodeRegressionProvider::OnCustomTimeStepChanged); ReinitRegressionBuffer(); return true; } return false; } void UTimecodeRegressionProvider::Shutdown(UEngine* InEngine) { TimecodeImpl->Shutdown(InEngine); OwningEngine->OnCustomTimeStepChanged().RemoveAll(this); OwningEngine = nullptr; } void UTimecodeRegressionProvider::ReinitRegressionBuffer() { check(IsInitialized()); UEngineCustomTimeStep* Timestep = OwningEngine->GetCustomTimeStep(); IClockedTimeStep* ClockedTimeStep = Timestep ? Cast(Timestep) : nullptr; UE_CLOG(Timestep && !ClockedTimeStep, LogTimeManagement, Error, TEXT("Current timestep %s must implement the IClockedTimeStep in order to be used with UTimecodeRegressionProvider"), *Timestep->GetName() ); if (ClockedTimeStep) { EstimationState.Emplace(FMath::Clamp(NumSampledFrames, 1, 65536), *TimecodeImpl, *ClockedTimeStep); } else { EstimationState.Reset(); } }