// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "NiagaraCommon.h" #include "NiagaraDigestDatabase.h" #include "NiagaraGraphDigestTypes.h" #include "NiagaraHlslTranslator.h" #include "NiagaraParameterMapHistory.h" #include "NiagaraScriptSourceBase.h" #include "NiagaraSimulationStageCompileData.h" #include "NiagaraTypes.h" #include "Templates/SharedPointer.h" class FCompileConstantResolver; class FNiagaraCompilationGraph; class FNiagaraCompilationNodeEmitter; class FNiagaraCompileRequestData; class FNiagaraCompileRequestDuplicateData; struct FNiagaraCompilationDigestBridge; class FNiagaraFixedConstantResolver; enum class ENiagaraFunctionDebugState : uint8; class UNiagaraGraph; struct FNiagaraGraphCachedBuiltHistory; template class TNiagaraHlslTranslator; class UNiagaraScriptSourceBase; struct FNiagaraSystemCompilationTask; // a version of the FCompileConstantResolver that is immutable (the constants are evaluated at the time of // construction rather than on demand). Useful for digested graphs where their state is also immutable and // means we don't need to hold and reference UObjects (like UNiagaraSystem & UNiagaraEmitter) class FNiagaraFixedConstantResolver { public: using FTranslator = TNiagaraHlslTranslator; FNiagaraFixedConstantResolver(); FNiagaraFixedConstantResolver(const FTranslator* InTranslator, ENiagaraScriptUsage InUsage = ENiagaraScriptUsage::Function, ENiagaraFunctionDebugState InDebugState = ENiagaraFunctionDebugState::NoDebug); FNiagaraFixedConstantResolver(const FCompileConstantResolver& SrcConstantResolver); bool ResolveConstant(FNiagaraVariable& OutConstant) const; FNiagaraFixedConstantResolver WithDebugState(ENiagaraFunctionDebugState InDebugState) const; FNiagaraFixedConstantResolver WithUsage(ENiagaraScriptUsage ScriptUsage) const; ENiagaraFunctionDebugState GetDebugState() const; void AddChildResolver(const FGuid& ChildId, const FNiagaraFixedConstantResolver& ChildResolver); const FNiagaraFixedConstantResolver* FindChildResolver(const FGuid& ChildId) const; private: void InitConstants(); void SetScriptUsage(ENiagaraScriptUsage ScriptUsage); void SetDebugState(ENiagaraFunctionDebugState DebugState); const FTranslator* Translator = nullptr; enum class EResolvedConstant : uint8 { FunctionDebugState = 0, ScriptUsage, ScriptContext, EmitterLocalspace, EmitterDeterminism, EmitterInterpolatedSpawn, EmitterSimulationTarget, Count }; TArray> ResolvedConstants; using FNamedResolverPair = TTuple; TArray ChildResolvers; }; struct FNiagaraSimulationStageInfo { FGuid StageId; bool bEnabled = true; bool bGenericStage = false; ENiagaraIterationSource IterationSource = ENiagaraIterationSource::Particles; FName DataInterfaceBindingName; bool bHasCompilationData = false; FNiagaraSimulationStageCompilationData CompilationData; }; ////////////////////////////////////////////////////////////////////////// // Helper structures for the FNiagaraActiveCompilationAsyncTask ////////////////////////////////////////////////////////////////////////// // holds the precompile data for the compilation of a NiagaraSystem class FNiagaraPrecompileData { public: using FSharedPrecompileData = TSharedPtr; void GatherPreCompiledVariables(const FString& InNamespaceFilter, TArray& OutVars) const; FName ResolveEmitterAlias(FName VariableName) const; const FString& GetUniqueEmitterName() const { return EmitterUniqueName; } FNiagaraEmitterID GetEmitterID()const { return EmitterID; } void FinishPrecompile( const FNiagaraSystemCompilationTask& CompilationTask, TConstArrayView EncounterableVariables, TConstArrayView InStaticVariables, const FNiagaraFixedConstantResolver& ConstantResolver, TConstArrayView UsagesToProcess, TConstArrayView SimStages, TConstArrayView EmitterNames); void CollectBakedRapidIterationParameters(const FNiagaraSystemCompilationTask& CompilationTask, TConstArrayView> OwnedScriptKeys); int32 GetDependentRequestCount() const { return EmitterData.Num(); }; FSharedPrecompileData GetDependentRequest(int32 Index) { return EmitterData[Index]; } const FNiagaraPrecompileData* GetDependentRequest(int32 Index) const { return EmitterData[Index].Get(); } bool GetUseRapidIterationParams() const { return bUseRapidIterationParams; } bool GetDisableDebugSwitches() const { return bDisableDebugSwitches; } bool Matches(const FNiagaraCompileRequestData& Other) const; // Simulation Stage Variables. Sim stage of 0 is always Spawn/Update TArray CompileSimStageData; struct FCompileDataInterfaceData { FString EmitterName; ENiagaraScriptUsage Usage; FGuid UsageId; FNiagaraVariable Variable; TArray ReadsEmitterParticleData; }; TSharedPtr> SharedCompileDataInterfaceData; TArray EncounteredVariables; FString EmitterUniqueName; FNiagaraEmitterID EmitterID; TArray EmitterData; FNiagaraDigestedGraphPtr DigestedSourceGraph; FString SourceName; bool bUseRapidIterationParams = true; bool bDisableDebugSwitches = false; UEnum* ENiagaraScriptCompileStatusEnum = nullptr; UEnum* ENiagaraScriptUsageEnum = nullptr; TMap PinToConstantValues; TArray StaticVariables; TArray StaticVariablesWithMultipleWrites; TArray BakedRapidIterationParameters; static void SortOutputNodesByDependencies(TArray& NodesToSort, TConstArrayView SimStages); template T GetStaticVariableValue(const FNiagaraVariableBase Variable, const T DefaultValue) const { const int32 Index = StaticVariables.Find(Variable); return Index != INDEX_NONE && StaticVariables[Index].IsDataAllocated() ? StaticVariables[Index].GetValue() : DefaultValue; } }; class FNiagaraCompilationCopyData { public: using FSharedCompilationCopy = TSharedPtr; using FParameterMapHistory = TNiagaraParameterMapHistory; using FParameterMapHistoryWithMetaDataBuilder = TNiagaraParameterMapHistoryWithMetaDataBuilder; UNiagaraDataInterface* GetDuplicatedDataInterfaceCDOForClass(UClass* Class) const; TArray& GetPrecomputedHistories() { return PrecompiledHistories; } const TArray& GetPrecomputedHistories() const { return PrecompiledHistories; } void InstantiateCompilationCopy(const FNiagaraCompilationGraphDigested& SourceGraph, const FNiagaraPrecompileData* PrecompileData, ENiagaraScriptUsage InUsage, const FNiagaraFixedConstantResolver& ConstantResolver); void CreateParameterMapHistory(const FNiagaraSystemCompilationTask& CompilationTask, const TArray& EncounterableVariables, const TArray& InStaticVariables, const FNiagaraFixedConstantResolver& ConstantResolver, TConstArrayView SimStages); int32 GetDependentRequestCount() const { return EmitterData.Num(); } FSharedCompilationCopy GetDependentRequest(int32 Index) { return EmitterData[Index]; } TArray ValidUsages; TSharedPtr InstantiatedGraph; TArray PrecompiledHistories; TArray ChangedFromNumericVars; FString EmitterUniqueName; TArray EmitterData; TMap, TObjectPtr> AggregatedDataInterfaceCDODuplicates; }; ////////////////////////////////////////////////////////////////////////// // Helper structures for the FNiagaraActiveCompilationDefault ////////////////////////////////////////////////////////////////////////// // Implements the FNiagaraCompileRequestDataBase interface that is used to represent the precompile data // in order to perform the compilation of a Niagara asset. class FNiagaraCompileRequestData : public FNiagaraCompileRequestDataBase { public: FNiagaraCompileRequestData() { } virtual void GatherPreCompiledVariables(const FString& InNamespaceFilter, TArray& OutVars) const override; virtual FName ResolveEmitterAlias(FName VariableName) const override; const FString& GetUniqueEmitterName() const { return EmitterUniqueName; } void FinishPrecompile(const TArray& EncounterableVariables, const TArray& InStaticVariables, FCompileConstantResolver ConstantResolver, const TArray& UsagesToProcess, const TArray* SimStages, const TArray EmitterNames); virtual int32 GetDependentRequestCount() const override { return EmitterData.Num(); }; virtual TSharedPtr GetDependentRequest(int32 Index) override { return EmitterData[Index]; } virtual const FNiagaraCompileRequestDataBase* GetDependentRequest(int32 Index) const override { return EmitterData[Index].Get(); } void AddRapidIterationParameters(const FNiagaraParameterStore& InParamStore, FCompileConstantResolver InResolver); virtual bool GetUseRapidIterationParams() const override { return bUseRapidIterationParams; } virtual bool GetDisableDebugSwitches() const override { return bDisableDebugSwitches; } // Simulation Stage Variables. Sim stage of 0 is always Spawn/Update TArray CompileSimStageData; struct FCompileDataInterfaceData { FString EmitterName; ENiagaraScriptUsage Usage; FGuid UsageId; FNiagaraVariable Variable; TArray ReadsEmitterParticleData; }; TSharedPtr> SharedCompileDataInterfaceData; TArray EncounteredVariables; FString EmitterUniqueName; FNiagaraEmitterID EmitterID; TArray> EmitterData; TWeakObjectPtr Source; FString SourceName; bool bUseRapidIterationParams = true; bool bDisableDebugSwitches = false; UEnum* ENiagaraScriptCompileStatusEnum = nullptr; UEnum* ENiagaraScriptUsageEnum = nullptr; TArray RapidIterationParams; TMap PinToConstantValues; TArray StaticVariables; TArray StaticVariablesWithMultipleWrites; template T GetStaticVariableValue(const FNiagaraVariableBase Variable, const T DefaultValue) const { const int32 Index = StaticVariables.Find(Variable); return Index != INDEX_NONE && StaticVariables[Index].IsDataAllocated() ? StaticVariables[Index].GetValue() : DefaultValue; } void CompareAgainst(FNiagaraGraphCachedBuiltHistory* InCachedDataBase); static void SortOutputNodesByDependencies(TArray& NodesToSort, const TArray* SimStages); }; // Implements the FNiagaraCompileRequestDuplicateDataBase interface that is used to represent the data that // is duplicated (for example graphs) in order to perform the compilation of a Niagara asset. class FNiagaraCompileRequestDuplicateData : public FNiagaraCompileRequestDuplicateDataBase { public: FNiagaraCompileRequestDuplicateData() { } virtual bool IsDuplicateDataFor(UNiagaraSystem* InSystem, UNiagaraEmitter* InEmitter, UNiagaraScript* InScript) const override; virtual void GetDuplicatedObjects(TArray& Objects) override; virtual const TMap& GetObjectNameMap() override; virtual const UNiagaraScriptSourceBase* GetScriptSource() const override; UNiagaraDataInterface* GetDuplicatedDataInterfaceCDOForClass(UClass* Class) const; TArray& GetPrecomputedHistories() { return PrecompiledHistories; } const TArray& GetPrecomputedHistories() const { return PrecompiledHistories; } void DuplicateReferencedGraphs(UNiagaraGraph* InSrcGraph, UNiagaraGraph* InDupeGraph, ENiagaraScriptUsage InUsage, FCompileConstantResolver ConstantResolver, TMap FunctionsWithUsage = TMap()); void DeepCopyGraphs(UNiagaraScriptSource* ScriptSource, ENiagaraScriptUsage InUsage, FCompileConstantResolver ConstantResolver); void DeepCopyGraphs(const FVersionedNiagaraEmitter& Emitter); void FinishPrecompileDuplicate(const TArray& EncounterableVariables, const TArray& InStaticVariables, FCompileConstantResolver ConstantResolver, const TArray* SimStages, const TArray& InParamStore); void CreateDataInterfaceCDO(TArrayView VariableDataInterfaces); virtual int32 GetDependentRequestCount() const override { return EmitterData.Num(); } virtual TSharedPtr GetDependentRequest(int32 Index) override { return EmitterData[Index]; } virtual void ReleaseCompilationCopies() override; TWeakObjectPtr OwningSystem; TWeakObjectPtr OwningEmitter; TArray ValidUsages; TWeakObjectPtr SourceDeepCopy; TWeakObjectPtr NodeGraphDeepCopy; TArray PrecompiledHistories; TArray ChangedFromNumericVars; FString EmitterUniqueName; FNiagaraEmitterID EmitterID; TArray> EmitterData; struct FDuplicatedGraphData { UNiagaraScript* ClonedScript; UNiagaraGraph* ClonedGraph; TArray CallInputs; TArray CallOutputs; ENiagaraScriptUsage Usage; bool bHasNumericParameters; }; TSharedPtr>> SharedSourceGraphToDuplicatedGraphsMap; TSharedPtr> SharedNameToDuplicatedDataInterfaceMap; TSharedPtr> SharedDataInterfaceClassToDuplicatedCDOMap; protected: void DuplicateReferencedGraphsRecursive(UNiagaraGraph* InGraph, const FCompileConstantResolver& ConstantResolver, TMap FunctionsWithUsage); private: TArray> TrackedScriptSourceCopies; }; enum class ENiagaraCompileRIParamMode : uint8 { // the issue here is that we aren't strictly allowed to call ComputeVMCompilationId on the worker threads which leaves us in a // state where we could have broken RI parameters. We ensure that the RI parameters are up to date before we begin. This is a // costly operation, but sadly seems necessary for some content. GameThread = 0, // for now we need RI generation to be synchronous to match the behavior of the default // compilation mode. In the future we need to get RI preparation out of the compilation // and instead we are provided with overridden RI values and don't need to feed back the // entire list of RI parameters. WorkerThread_Synchronous, // desirable behavior that currently doesn't work WorkerThread_Asynchronous, };