// Copyright Epic Games, Inc. All Rights Reserved. #pragma once inline FRDGTexture* FRDGBuilder::FindExternalTexture(FRHITexture* ExternalTexture) const { if (FRDGTexture* const* FoundTexturePtr = ExternalTextures.Find(ExternalTexture)) { return *FoundTexturePtr; } return nullptr; } inline FRDGTexture* FRDGBuilder::FindExternalTexture(IPooledRenderTarget* ExternalTexture) const { if (ExternalTexture) { return FindExternalTexture(ExternalTexture->GetRHI()); } return nullptr; } inline FRDGBuffer* FRDGBuilder::FindExternalBuffer(FRHIBuffer* ExternalBuffer) const { if (FRDGBuffer* const* FoundBufferPtr = ExternalBuffers.Find(ExternalBuffer)) { return *FoundBufferPtr; } return nullptr; } inline FRDGBuffer* FRDGBuilder::FindExternalBuffer(FRDGPooledBuffer* ExternalBuffer) const { if (ExternalBuffer) { return FindExternalBuffer(ExternalBuffer->GetRHI()); } return nullptr; } inline FRDGTextureRef FRDGBuilder::CreateTexture( const FRDGTextureDesc& Desc, const TCHAR* Name, ERDGTextureFlags Flags) { FRDGTextureDesc OverrideDesc = Desc; #if !UE_BUILD_SHIPPING ensureMsgf(OverrideDesc.Extent.X >= 1, TEXT("CreateTexture %s X size too small: %i, Min: %i, clamping"), Name ? Name : TEXT(""), OverrideDesc.Extent.X, 1); ensureMsgf(OverrideDesc.Extent.Y >= 1, TEXT("CreateTexture %s Y size too small: %i, Min: %i, clamping"), Name ? Name : TEXT(""), OverrideDesc.Extent.Y, 1); ensureMsgf(((uint32)OverrideDesc.Extent.X) <= GetMax2DTextureDimension(), TEXT("CreateTexture %s X size too large: %i, Max: %i, clamping"), Name ? Name : TEXT(""), OverrideDesc.Extent.X, GetMax2DTextureDimension()); ensureMsgf(((uint32)OverrideDesc.Extent.Y) <= GetMax2DTextureDimension(), TEXT("CreateTexture %s Y size too large: %i, Max: %i, clamping"), Name ? Name : TEXT(""), OverrideDesc.Extent.Y, GetMax2DTextureDimension()); #endif // Clamp the texture size to that which is permissible, otherwise it's a guaranteed crash. OverrideDesc.Extent.X = FMath::Clamp(OverrideDesc.Extent.X, 1, GetMax2DTextureDimension()); OverrideDesc.Extent.Y = FMath::Clamp(OverrideDesc.Extent.Y, 1, GetMax2DTextureDimension()); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateTexture(OverrideDesc, Name, Flags)); FRDGTextureRef Texture = Textures.Allocate(Allocators.Root, Name, OverrideDesc, Flags); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateTexture(Texture)); IF_RDG_ENABLE_TRACE(Trace.AddResource(Texture)); return Texture; } inline FRDGBufferRef FRDGBuilder::CreateBuffer( const FRDGBufferDesc& Desc, const TCHAR* Name, ERDGBufferFlags Flags) { FRDGBufferDesc OverrideDesc = Desc; IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateBuffer(OverrideDesc, Name, Flags)); // Clamp the buffer size to that which is permissible, otherwise it's a guaranteed crash. OverrideDesc.BytesPerElement = FMath::Max(1u, OverrideDesc.BytesPerElement); OverrideDesc.NumElements = FMath::Max(1u, OverrideDesc.NumElements); FRDGBufferRef Buffer = Buffers.Allocate(Allocators.Root, Name, OverrideDesc, Flags); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateBuffer(Buffer)); IF_RDG_ENABLE_TRACE(Trace.AddResource(Buffer)); return Buffer; } inline FRDGBufferRef FRDGBuilder::CreateBuffer( const FRDGBufferDesc& Desc, const TCHAR* Name, FRDGBufferNumElementsCallback&& InNumElementsCallback, ERDGBufferFlags Flags) { // RDG no longer supports the legacy transient resource API. FRDGBufferDesc OverrideDesc = Desc; IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateBuffer(Desc, Name, Flags)); FRDGBufferNumElementsCallback* NumElementsCallback = InNumElementsCallback ? Allocators.Root.AllocNoDestruct(MoveTemp(InNumElementsCallback)) : nullptr; FRDGBufferRef Buffer = Buffers.Allocate(Allocators.Root, Name, OverrideDesc, Flags, NumElementsCallback); NumElementsCallbackBuffers.Emplace(Buffer); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateBuffer(Buffer)); IF_RDG_ENABLE_TRACE(Trace.AddResource(Buffer)); return Buffer; } inline FRDGTextureSRVRef FRDGBuilder::CreateSRV(const FRDGTextureSRVDesc& Desc) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateSRV(Desc)); FRDGTextureSRVRef SRV = Views.Allocate(Allocators.Root, Desc.Texture->Name, Desc); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateSRV(SRV)); return SRV; } inline FRDGBufferSRVRef FRDGBuilder::CreateSRV(const FRDGBufferSRVDesc& Desc) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateSRV(Desc)); FRDGBufferSRVRef SRV = Views.Allocate(Allocators.Root, Desc.Buffer->Name, Desc); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateSRV(SRV)); return SRV; } inline FRDGTextureUAVRef FRDGBuilder::CreateUAV(const FRDGTextureUAVDesc& Desc, ERDGUnorderedAccessViewFlags InFlags) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUAV(Desc)); FRDGTextureUAVRef UAV = Views.Allocate(Allocators.Root, Desc.Texture->Name, Desc, InFlags); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUAV(UAV)); return UAV; } inline FRDGBufferUAVRef FRDGBuilder::CreateUAV(const FRDGBufferUAVDesc& Desc, ERDGUnorderedAccessViewFlags InFlags) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUAV(Desc)); FRDGBufferUAVRef UAV = Views.Allocate(Allocators.Root, Desc.Buffer->Name, Desc, InFlags); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUAV(UAV)); return UAV; } FORCEINLINE void* FRDGBuilder::Alloc(uint64 SizeInBytes, uint32 AlignInBytes) { return Allocators.Root.Alloc(SizeInBytes, AlignInBytes); } template FORCEINLINE PODType* FRDGBuilder::AllocPOD() { return Allocators.Root.AllocUninitialized(); } template FORCEINLINE PODType* FRDGBuilder::AllocPODArray(uint32 Count) { return Allocators.Root.AllocUninitialized(Count); } template TArrayView FRDGBuilder::AllocPODArrayView(uint32 Count) { return TArrayView(AllocPODArray(Count), Count); } template FORCEINLINE ObjectType* FRDGBuilder::AllocObject(TArgs&&... Args) { return Allocators.Root.Alloc(Forward(Args)...); } template FORCEINLINE TArray& FRDGBuilder::AllocArray() { return *Allocators.Root.Alloc>(); } template FORCEINLINE ParameterStructType* FRDGBuilder::AllocParameters() { return Allocators.Root.Alloc(); } template FORCEINLINE ParameterStructType* FRDGBuilder::AllocParameters(const ParameterStructType* StructToCopy) { ParameterStructType* Struct = Allocators.Root.Alloc(); *Struct = *StructToCopy; return Struct; } template BaseParameterStructType* FRDGBuilder::AllocParameters(const FShaderParametersMetadata* ParametersMetadata) { return &AllocParameters(ParametersMetadata, 1)[0]; } template TStridedView FRDGBuilder::AllocParameters(const FShaderParametersMetadata* ParametersMetadata, uint32 NumStructs) { // NOTE: Contents are always zero! This might differ if shader parameters have a non-zero default initializer. const int32 Stride = ParametersMetadata->GetSize(); BaseParameterStructType* Contents = reinterpret_cast(Allocators.Root.Alloc(Stride * NumStructs, SHADER_PARAMETER_STRUCT_ALIGNMENT)); FMemory::Memset(Contents, 0, Stride * NumStructs); TStridedView ParameterArray(Stride, Contents, NumStructs); struct FClearUniformBuffers { public: FClearUniformBuffers(TStridedView InParameterArray, const FRHIUniformBufferLayout& InLayout) : ParameterArray(InParameterArray) , Layout(&InLayout) {} ~FClearUniformBuffers() { for (BaseParameterStructType& ParameterStruct : ParameterArray) { FRDGParameterStruct::ClearUniformBuffers(&ParameterStruct, Layout); } } private: TStridedView ParameterArray; const FRHIUniformBufferLayout* Layout; }; AllocObject(ParameterArray, ParametersMetadata->GetLayout()); return ParameterArray; } FORCEINLINE FRDGSubresourceState* FRDGBuilder::AllocSubresource(const FRDGSubresourceState& Other) { return Allocators.Transition.AllocNoDestruct(Other); } FORCEINLINE FRDGSubresourceState* FRDGBuilder::AllocSubresource() { return Allocators.Transition.AllocNoDestruct(); } template TRDGUniformBufferRef FRDGBuilder::CreateUniformBuffer(const ParameterStructType* ParameterStruct) { #if !USE_NULL_RHI IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUniformBuffer(ParameterStruct, ParameterStructType::FTypeInfo::GetStructMetadata())); auto* UniformBuffer = UniformBuffers.Allocate>(Allocators.Root, ParameterStruct, ParameterStructType::FTypeInfo::GetStructMetadata()->GetShaderVariableName()); IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCreateUniformBuffer(UniformBuffer)); return UniformBuffer; #else checkNoEntry(); return nullptr; #endif // !USE_NULL_RHI } #if !USE_NULL_RHI template FRDGPass* FRDGBuilder::AddPassInternal( FRDGEventName&& Name, const FShaderParametersMetadata* ParametersMetadata, const ParameterStructType* ParameterStruct, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda) { using LambdaPassType = TRDGLambdaPass; IF_RDG_ENABLE_DEBUG(UserValidation.ValidateAddPass(ParameterStruct, ParametersMetadata, Name, Flags)); FlushAccessModeQueue(); const TCHAR* NameString = Name.GetTCHAR(); FRDGPass* Pass = Allocators.Root.AllocNoDestruct( Forward(Name), ParametersMetadata, ParameterStruct, OverridePassFlags(NameString, Flags), Forward(ExecuteLambda)); IF_RDG_ENABLE_DEBUG(ClobberPassOutputs(Pass)); Passes.Insert(Pass); SetupParameterPass(Pass); return Pass; } #endif // !USE_NULL_RHI template FRDGPass* FRDGBuilder::AddPass( FRDGEventName&& Name, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda) { #if !USE_NULL_RHI using LambdaPassType = TRDGEmptyLambdaPass; IF_RDG_ENABLE_DEBUG(UserValidation.ValidateAddPass(Name, Flags)); Flags |= ERDGPassFlags::NeverCull; FlushAccessModeQueue(); LambdaPassType* Pass = Passes.Allocate(Allocators.Root, Forward(Name), Flags, Forward(ExecuteLambda)); SetupEmptyPass(Pass); return Pass; #else checkNoEntry(); return nullptr; #endif // !USE_NULL_RHI } template FRDGPass* FRDGBuilder::AddPass( FRDGEventName&& Name, const FShaderParametersMetadata* ParametersMetadata, const void* ParameterStruct, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda) { #if !USE_NULL_RHI return AddPassInternal(Forward(Name), ParametersMetadata, ParameterStruct, Flags, Forward(ExecuteLambda)); #else checkNoEntry(); return nullptr; #endif // !USE_NULL_RHI } template FRDGPass* FRDGBuilder::AddPass( FRDGEventName&& Name, const ParameterStructType* ParameterStruct, ERDGPassFlags Flags, ExecuteLambdaType&& ExecuteLambda) { #if !USE_NULL_RHI return AddPassInternal(Forward(Name), ParameterStructType::FTypeInfo::GetStructMetadata(), ParameterStruct, Flags, Forward(ExecuteLambda)); #else checkNoEntry(); return nullptr; #endif // !USE_NULL_RHI } template FRDGPass* FRDGBuilder::AddDispatchPass( FRDGEventName&& Name, const ParameterStructType* ParameterStruct, ERDGPassFlags Flags, LaunchLambdaType&& LaunchLambda) { #if !USE_NULL_RHI using DispatchPassType = TRDGDispatchPass; const FShaderParametersMetadata* ParametersMetadata = ParameterStructType::FTypeInfo::GetStructMetadata(); if (EnumHasAnyFlags(Flags, ERDGPassFlags::Raster)) { Flags |= ERDGPassFlags::SkipRenderPass; } IF_RDG_ENABLE_DEBUG(UserValidation.ValidateAddPass(ParameterStruct, ParametersMetadata, Name, Flags)); FlushAccessModeQueue(); const TCHAR* NameString = Name.GetTCHAR(); FRDGDispatchPass* Pass = Allocators.Root.AllocNoDestruct( Forward(Name), ParametersMetadata, ParameterStruct, OverridePassFlags(NameString, Flags), Forward(LaunchLambda)); IF_RDG_ENABLE_DEBUG(ClobberPassOutputs(Pass)); Passes.Insert(Pass); DispatchPasses.Emplace(Pass); SetupParameterPass(Pass); return Pass; #else checkNoEntry(); return nullptr; #endif // !USE_NULL_RHI } inline void FRDGBuilder::SetPassWorkload(FRDGPass* Pass, uint32 Workload) { Pass->Workload = Workload; } inline void FRDGBuilder::SkipInitialAsyncComputeFence() { bInitialAsyncComputeFence = false; } inline void FRDGBuilder::QueueBufferUpload(FRDGBufferRef Buffer, const void* InitialData, uint64 InitialDataSize, ERDGInitialDataFlags InitialDataFlags) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateUploadBuffer(Buffer, InitialData, InitialDataSize)); if (InitialDataSize > 0 && !EnumHasAnyFlags(InitialDataFlags, ERDGInitialDataFlags::NoCopy)) { void* InitialDataCopy = Alloc(InitialDataSize, 16); FMemory::Memcpy(InitialDataCopy, InitialData, InitialDataSize); InitialData = InitialDataCopy; } UploadedBuffers.Emplace(Buffer, InitialData, InitialDataSize); Buffer->bQueuedForUpload = 1; } inline void FRDGBuilder::QueueBufferUpload(FRDGBufferRef Buffer, const void* InitialData, uint64 InitialDataSize, FRDGBufferInitialDataFreeCallback&& InitialDataFreeCallback) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateUploadBuffer(Buffer, InitialData, InitialDataSize)); if (InitialDataSize == 0) { return; } UploadedBuffers.Emplace(Buffer, InitialData, InitialDataSize, MoveTemp(InitialDataFreeCallback)); Buffer->bQueuedForUpload = 1; } inline void FRDGBuilder::QueueBufferUpload(FRDGBufferRef Buffer, FRDGBufferInitialDataFillCallback&& InitialDataFillCallback) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateUploadBuffer(Buffer, InitialDataFillCallback)); UploadedBuffers.Emplace(Buffer, MoveTemp(InitialDataFillCallback)); Buffer->bQueuedForUpload = 1; } inline void FRDGBuilder::QueueBufferUpload(FRDGBufferRef Buffer, FRDGBufferInitialDataCallback&& InitialDataCallback, FRDGBufferInitialDataSizeCallback&& InitialDataSizeCallback) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateUploadBuffer(Buffer, InitialDataCallback, InitialDataSizeCallback)); UploadedBuffers.Emplace(Buffer, MoveTemp(InitialDataCallback), MoveTemp(InitialDataSizeCallback)); Buffer->bQueuedForUpload = 1; } inline void FRDGBuilder::QueueBufferUpload(FRDGBufferRef Buffer, FRDGBufferInitialDataCallback&& InitialDataCallback, FRDGBufferInitialDataSizeCallback&& InitialDataSizeCallback, FRDGBufferInitialDataFreeCallback&& InitialDataFreeCallback) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateUploadBuffer(Buffer, InitialDataCallback, InitialDataSizeCallback, InitialDataFreeCallback)); UploadedBuffers.Emplace(Buffer, MoveTemp(InitialDataCallback), MoveTemp(InitialDataSizeCallback), MoveTemp(InitialDataFreeCallback)); Buffer->bQueuedForUpload = 1; } inline void FRDGBuilder::QueueCommitReservedBuffer(FRDGBufferRef Buffer, uint64 CommitSizeInBytes) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateCommitBuffer(Buffer, CommitSizeInBytes)); if (!AsyncSetupQueue.bEnabled) { Buffer->PendingCommitSize = CommitSizeInBytes; } else { AsyncSetupQueue.Push(FAsyncSetupOp::ReservedBufferCommit(Buffer, CommitSizeInBytes)); } Buffer->PooledBuffer->SetCommittedSize(CommitSizeInBytes); } inline void FRDGBuilder::QueueTextureExtraction(FRDGTextureRef Texture, TRefCountPtr* OutTexturePtr, ERHIAccess AccessFinal, ERDGResourceExtractionFlags Flags) { QueueTextureExtraction(Texture, OutTexturePtr, Flags); SetTextureAccessFinal(Texture, AccessFinal); } inline void FRDGBuilder::QueueTextureExtraction(FRDGTextureRef Texture, TRefCountPtr* OutTexturePtr, ERDGResourceExtractionFlags Flags) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateExtractTexture(Texture, OutTexturePtr)); *OutTexturePtr = nullptr; const bool bWasExtracted = Texture->bExtracted; Texture->bExtracted = true; if (EnumHasAnyFlags(Flags, ERDGResourceExtractionFlags::AllowTransient)) { if (Texture->TransientExtractionHint != FRDGTexture::ETransientExtractionHint::Disable) { Texture->TransientExtractionHint = FRDGTexture::ETransientExtractionHint::Enable; } } else { Texture->TransientExtractionHint = FRDGTexture::ETransientExtractionHint::Disable; } ExtractedTextures.Emplace(Texture, OutTexturePtr); if (!bWasExtracted) { AsyncSetupQueue.Push(FAsyncSetupOp::CullRootTexture(Texture)); } } inline void FRDGBuilder::QueueBufferExtraction(FRDGBufferRef Buffer, TRefCountPtr* OutBufferPtr) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateExtractBuffer(Buffer, OutBufferPtr)); *OutBufferPtr = nullptr; const bool bWasExtracted = Buffer->bExtracted; Buffer->bExtracted = true; Buffer->bForceNonTransient = true; ExtractedBuffers.Emplace(Buffer, OutBufferPtr); if (!bWasExtracted) { AsyncSetupQueue.Push(FAsyncSetupOp::CullRootBuffer(Buffer)); } } inline void FRDGBuilder::QueueBufferExtraction(FRDGBufferRef Buffer, TRefCountPtr* OutBufferPtr, ERHIAccess AccessFinal) { QueueBufferExtraction(Buffer, OutBufferPtr); SetBufferAccessFinal(Buffer, AccessFinal); } inline void FRDGBuilder::AddDispatchHint() { if (IsImmediateMode()) { RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); } else if (Passes.Num() > 0) { Passes[Passes.Last()]->bDispatchAfterExecute = 1; } } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddSetupTask(TaskLambdaType&& TaskLambda, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddSetupTask(MoveTemp(TaskLambda), nullptr, TArray{}, UE::Tasks::ETaskPriority::Normal, bCondition, WaitPoint); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddSetupTask(TaskLambdaType&& TaskLambda, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddSetupTask(MoveTemp(TaskLambda), nullptr, TArray{}, Priority, bCondition, WaitPoint); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddSetupTask( TaskLambdaType&& TaskLambda, UE::Tasks::FPipe* Pipe, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddSetupTask(MoveTemp(TaskLambda), Pipe, TArray{}, Priority, bCondition); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddSetupTask( TaskLambdaType&& TaskLambda, PrerequisitesCollectionType&& Prerequisites, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddSetupTask(MoveTemp(TaskLambda), nullptr, Forward(Prerequisites), Priority, bCondition); } namespace UE::RDG { template().begin())* = nullptr> inline bool IsCompleted(const TaskCollectionType& Tasks) { for (const UE::Tasks::FTask& Task : Tasks) { if (!Task.IsCompleted()) { return false; } } return true; } template().IsCompleted())* = nullptr> inline bool IsCompleted(const TaskType& Task) { return Task.IsCompleted(); } template().begin())* = nullptr> inline void Wait(const TaskCollectionType& Tasks) { if (!Tasks.IsEmpty()) { UE::Tasks::Wait(Tasks); } } template().Wait())* = nullptr> inline void Wait(const TaskType& Task) { Task.Wait(); } } template UE::Tasks::FTask FRDGBuilder::AddSetupTask( TaskLambdaType&& TaskLambda, UE::Tasks::FPipe* Pipe, PrerequisitesCollectionType&& Prerequisites, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { UE::Tasks::FTask Task; if (!bCondition || IsImmediateMode()) { UE::RDG::Wait(Prerequisites); } auto OuterLambda = [TaskLambda = MoveTemp(TaskLambda)]() mutable { FTaskTagScope Scope(ETaskTag::EParallelRenderingThread); TaskLambda(); }; const UE::Tasks::EExtendedTaskPriority ExtendedTaskPriority = ParallelSetup.bEnabled ? UE::Tasks::EExtendedTaskPriority::None : UE::Tasks::EExtendedTaskPriority::Inline; const bool bParallelEnabled = bCompiling ? bParallelCompileEnabled : ParallelSetup.bEnabled; if (!bCondition || (!bParallelEnabled && UE::RDG::IsCompleted(Prerequisites))) { OuterLambda(); } else if (Pipe) { Task = Pipe->Launch(TEXT("FRDGBuilder::AddSetupTask"), MoveTemp(OuterLambda), Forward(Prerequisites), ParallelSetup.GetTaskPriority(Priority), ExtendedTaskPriority); } else { Task = UE::Tasks::Launch(TEXT("FRDGBuilder::AddSetupTask"), MoveTemp(OuterLambda), Forward(Prerequisites), ParallelSetup.GetTaskPriority(Priority), ExtendedTaskPriority); } if (Task.IsValid()) { ParallelSetup.Tasks[(int32)WaitPoint].Emplace(Task); } return Task; } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddCommandListSetupTask(TaskLambdaType&& TaskLambda, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddCommandListSetupTask(MoveTemp(TaskLambda), nullptr, TArray{}, UE::Tasks::ETaskPriority::Normal, bCondition, WaitPoint); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddCommandListSetupTask(TaskLambdaType&& TaskLambda, UE::Tasks::ETaskPriority TaskPriority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddCommandListSetupTask(MoveTemp(TaskLambda), nullptr, TArray{}, TaskPriority, bCondition, WaitPoint); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddCommandListSetupTask( TaskLambdaType&& TaskLambda, UE::Tasks::FPipe* Pipe, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddCommandListSetupTask(MoveTemp(TaskLambda), Pipe, TArray{}, Priority, bCondition, WaitPoint); } template FORCEINLINE UE::Tasks::FTask FRDGBuilder::AddCommandListSetupTask( TaskLambdaType&& TaskLambda, PrerequisitesCollectionType&& Prerequisites, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { return AddCommandListSetupTask(MoveTemp(TaskLambda), nullptr, Forward(Prerequisites), Priority, bCondition, WaitPoint); } template UE::Tasks::FTask FRDGBuilder::AddCommandListSetupTask( TaskLambdaType&& TaskLambda, UE::Tasks::FPipe* Pipe, PrerequisitesCollectionType&& Prerequisites, UE::Tasks::ETaskPriority Priority, bool bCondition, ERDGSetupTaskWaitPoint WaitPoint) { UE::Tasks::FTask Task; if (!bCondition || IsImmediateMode()) { UE::RDG::Wait(Prerequisites); } const bool bParallelEnabled = bCompiling ? bParallelCompileEnabled : ParallelSetup.bEnabled; // Need a separate command list with inline tasks when prerequisites are not complete yet. const bool bAllocateCommandListForTask = bCondition && (bParallelEnabled || !UE::RDG::IsCompleted(Prerequisites)); FRHICommandList* RHICmdListTask = &RHICmdList; if (bAllocateCommandListForTask) { SCOPED_NAMED_EVENT(CreateCommandList, FColor::Emerald); RHICmdListTask = new FRHICommandList(RHICmdList.GetGPUMask()); RHICmdList.QueueAsyncCommandListSubmit(RHICmdListTask); } auto OuterLambda = [this, TaskLambda = MoveTemp(TaskLambda), RHICmdListTask, bAllocateCommandListForTask]() mutable { FTaskTagScope Scope(ETaskTag::EParallelRenderingThread); if (bAllocateCommandListForTask) { RHICmdListTask->SwitchPipeline(ERHIPipeline::Graphics); } TaskLambda(*RHICmdListTask); if (bAllocateCommandListForTask) { RHICmdListTask->FinishRecording(); } }; const UE::Tasks::EExtendedTaskPriority ExtendedTaskPriority = bCondition ? UE::Tasks::EExtendedTaskPriority::None : UE::Tasks::EExtendedTaskPriority::Inline; if (!bAllocateCommandListForTask) { OuterLambda(); } else if (Pipe) { Task = Pipe->Launch(TEXT("FRDGBuilder::AddCommandListSetupTask"), MoveTemp(OuterLambda), Forward(Prerequisites), ParallelSetup.GetTaskPriority(Priority), ExtendedTaskPriority); } else { Task = UE::Tasks::Launch(TEXT("FRDGBuilder::AddCommandListSetupTask"), MoveTemp(OuterLambda), Forward(Prerequisites), ParallelSetup.GetTaskPriority(Priority), ExtendedTaskPriority); } if (Task.IsValid()) { ParallelSetup.Tasks[(int32)WaitPoint].Emplace(Task); } return Task; } inline const TRefCountPtr& FRDGBuilder::GetPooledTexture(FRDGTextureRef Texture) const { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateGetPooledTexture(Texture)); return Texture->Allocation; } inline const TRefCountPtr& FRDGBuilder::GetPooledBuffer(FRDGBufferRef Buffer) const { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateGetPooledBuffer(Buffer)); return Buffer->Allocation; } inline void FRDGBuilder::SetTextureAccessFinal(FRDGTextureRef Texture, ERHIAccess AccessFinal) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateSetAccessFinal(Texture, AccessFinal)); Texture->EpilogueAccess = AccessFinal; } inline void FRDGBuilder::SetBufferAccessFinal(FRDGBufferRef Buffer, ERHIAccess AccessFinal) { IF_RDG_ENABLE_DEBUG(UserValidation.ValidateSetAccessFinal(Buffer, AccessFinal)); Buffer->EpilogueAccess = AccessFinal; }