Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneCompiledVolatilityManager.cpp
2025-05-18 13:04:45 +08:00

195 lines
7.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Compilation/MovieSceneCompiledVolatilityManager.h"
#include "Compilation/MovieSceneCompiledDataManager.h"
#include "EntitySystem/MovieSceneSharedPlaybackState.h"
#include "MovieSceneFwd.h"
namespace UE
{
namespace MovieScene
{
#if WITH_EDITOR
int32 GVolatileSequencesInEditor = 1;
FAutoConsoleVariableRef CVarVolatileSequencesInEditor(
TEXT("Sequencer.VolatileSequencesInEditor"),
GVolatileSequencesInEditor,
TEXT("(Default: 1) When non-zero, all assets will be treated as volatile in editor. Can be disabled to bypass volatility checks in-editor for more representative runtime performance metrics.\n"),
ECVF_Default
);
#endif
FORCEINLINE EMovieSceneSequenceFlags GetEditorVolatilityFlags()
{
#if WITH_EDITOR
return GVolatileSequencesInEditor ? EMovieSceneSequenceFlags::Volatile : EMovieSceneSequenceFlags::None;
#else
return EMovieSceneSequenceFlags::None;
#endif
}
TUniquePtr<FCompiledDataVolatilityManager> FCompiledDataVolatilityManager::Construct(TSharedRef<const FSharedPlaybackState> SharedPlaybackState)
{
FMovieSceneCompiledDataID RootDataID = SharedPlaybackState->GetRootCompiledDataID();
UMovieSceneCompiledDataManager* CompiledDataManager = SharedPlaybackState->GetCompiledDataManager();
const FMovieSceneCompiledDataEntry& Entry = CompiledDataManager->GetEntryRef(RootDataID);
EMovieSceneSequenceFlags SequenceFlags = Entry.AccumulatedFlags | GetEditorVolatilityFlags();
if (!EnumHasAnyFlags(SequenceFlags, EMovieSceneSequenceFlags::Volatile))
{
// If the entry has a valid compiled signature, it is assumed to be non-volatile if it does
// not explicitly have the volatile flag. Otherwise we assume this sequence was added to the
// manager but never compiled, and as such must be volatile since it needs compiling.
if (Entry.CompiledSignature.IsValid())
{
return nullptr;
}
}
TUniquePtr<FCompiledDataVolatilityManager> VolatilityManager = MakeUnique<FCompiledDataVolatilityManager>(SharedPlaybackState);
VolatilityManager->ConditionalRecompile();
return VolatilityManager;
}
FCompiledDataVolatilityManager::FCompiledDataVolatilityManager(TSharedRef<const FSharedPlaybackState> SharedPlaybackState)
: WeakSharedPlaybackState(SharedPlaybackState)
{
}
bool FCompiledDataVolatilityManager::HasBeenRecompiled() const
{
TSharedPtr<const FSharedPlaybackState> SharedPlaybackState = WeakSharedPlaybackState.Pin();
FMovieSceneCompiledDataID RootDataID = SharedPlaybackState->GetRootCompiledDataID();
UMovieSceneCompiledDataManager* CompiledDataManager = SharedPlaybackState->GetCompiledDataManager();
if (HasSequenceBeenRecompiled(RootDataID, MovieSceneSequenceID::Root))
{
return true;
}
if (const FMovieSceneSequenceHierarchy* Hierarchy = CompiledDataManager->FindHierarchy(RootDataID))
{
for (const TTuple<FMovieSceneSequenceID, FMovieSceneSubSequenceData>& Pair : Hierarchy->AllSubSequenceData())
{
FMovieSceneCompiledDataID SubDataID = CompiledDataManager->GetSubDataID(RootDataID, Pair.Key);
if (SubDataID.IsValid() && HasSequenceBeenRecompiled(SubDataID, Pair.Key))
{
return true;
}
}
}
return false;
}
bool FCompiledDataVolatilityManager::HasSequenceBeenRecompiled(FMovieSceneCompiledDataID DataID, FMovieSceneSequenceID SequenceID) const
{
const FGuid* CachedSignature = CachedCompilationSignatures.Find(SequenceID);
TSharedPtr<const FSharedPlaybackState> SharedPlaybackState = WeakSharedPlaybackState.Pin();
UMovieSceneCompiledDataManager* CompiledDataManager = SharedPlaybackState->GetCompiledDataManager();
const FMovieSceneCompiledDataEntry& CompiledEntry = CompiledDataManager->GetEntryRef(DataID);
return CachedSignature == nullptr || *CachedSignature != CompiledEntry.CompiledSignature;
}
bool FCompiledDataVolatilityManager::ConditionalRecompile()
{
bool bRecompiled = false;
TSharedPtr<const FSharedPlaybackState> SharedPlaybackState = WeakSharedPlaybackState.Pin();
FMovieSceneCompiledDataID RootDataID = SharedPlaybackState->GetRootCompiledDataID();
UMovieSceneCompiledDataManager* CompiledDataManager = SharedPlaybackState->GetCompiledDataManager();
if (CompiledDataManager->IsDirty(RootDataID))
{
// We override the network mask from the compiled data manager here simply because it may not be correct.
// In a non-editor/PIE executable, we have a single global compiled data manager, and in its current 'global static' implementation,
// it may not have been created at a time with enough context to determine the net mode.
// In certain edge cases, such as networked games where both server and client are compiled using a single target executable of TargetType.Game,
// we may not have the context at Sequence cook/compile time to determine which subsections may be included/excluded at runtime based on NetworkMask,
// and so these Sequences are marked as volatile on compile time. Therefore, it's here, upon conditional recompile, when we need to know the correct
// network mask to use, which we override and apply here.
EMovieSceneServerClientMask NetworkMask = CompiledDataManager->GetNetworkMask();
UObject* PlaybackContext = SharedPlaybackState->GetPlaybackContext();
UWorld* World = PlaybackContext ? PlaybackContext->GetWorld() : nullptr;
if (World)
{
ENetMode NetMode = World->GetNetMode();
if (NetMode == ENetMode::NM_DedicatedServer)
{
NetworkMask = EMovieSceneServerClientMask::Server;
}
else if (NetMode == ENetMode::NM_Client)
{
NetworkMask = EMovieSceneServerClientMask::Client;
}
}
CompiledDataManager->Compile(RootDataID, NetworkMask);
bRecompiled = true;
}
else
{
bRecompiled = HasBeenRecompiled();
}
if (bRecompiled)
{
UpdateCachedSignatures();
}
return bRecompiled;
}
void FCompiledDataVolatilityManager::UpdateCachedSignatures()
{
CachedCompilationSignatures.Reset();
TSharedPtr<const FSharedPlaybackState> SharedPlaybackState = WeakSharedPlaybackState.Pin();
FMovieSceneCompiledDataID RootDataID = SharedPlaybackState->GetRootCompiledDataID();
UMovieSceneCompiledDataManager* CompiledDataManager = SharedPlaybackState->GetCompiledDataManager();
FMovieSceneEvaluationState* State = SharedPlaybackState->FindCapability<FMovieSceneEvaluationState>();
{
const FMovieSceneCompiledDataEntry& RootEntry = CompiledDataManager->GetEntryRef(RootDataID);
CachedCompilationSignatures.Add(MovieSceneSequenceID::Root, RootEntry.CompiledSignature);
UMovieSceneSequence* RootSequence = RootEntry.GetSequence();
if (RootSequence && State)
{
State->AssignSequence(MovieSceneSequenceID::Root, *RootSequence, SharedPlaybackState.ToSharedRef());
}
}
if (const FMovieSceneSequenceHierarchy* Hierarchy = CompiledDataManager->FindHierarchy(RootDataID))
{
for (const TTuple<FMovieSceneSequenceID, FMovieSceneSubSequenceData>& SubData : Hierarchy->AllSubSequenceData())
{
const FMovieSceneCompiledDataID SubDataID = CompiledDataManager->GetSubDataID(RootDataID, SubData.Key);
if (!SubDataID.IsValid())
{
UE_LOG(LogMovieScene, Error, TEXT("Invalid SubDataID for: %s"), *SubData.Value.Sequence.ToString());
continue;
}
const FMovieSceneCompiledDataEntry& SubEntry = CompiledDataManager->GetEntryRef(SubDataID);
CachedCompilationSignatures.Add(SubData.Key, SubEntry.CompiledSignature);
UMovieSceneSequence* Sequence = SubData.Value.GetSequence();
if (Sequence && State)
{
State->AssignSequence(SubData.Key, *Sequence, SharedPlaybackState.ToSharedRef());
}
}
}
}
} // namespace MovieScene
} // namespace UE