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

1025 lines
40 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RenderGraphUtils.h"
#include "ClearQuad.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "GlobalShader.h"
#include "PixelShaderUtils.h"
#include "RenderGraphResourcePool.h"
#include "RenderTargetPool.h"
#include "RHIGPUReadback.h"
#include <initializer_list>
void ClearUnusedGraphResourcesImpl(
const FShaderParameterBindings& ShaderBindings,
const FShaderParametersMetadata* ParametersMetadata,
void* InoutParameters,
std::initializer_list<FRDGResourceRef> ExcludeList)
{
const auto& GraphResources = ParametersMetadata->GetLayout().GraphResources;
int32 ShaderResourceIndex = 0;
int32 BindlessResourceIndex = 0;
int32 GraphUniformBufferId = 0;
uint8* const Base = reinterpret_cast<uint8*>(InoutParameters);
for (int32 GraphResourceIndex = 0, GraphResourceCount = GraphResources.Num(); GraphResourceIndex < GraphResourceCount; GraphResourceIndex++)
{
const EUniformBufferBaseType Type = GraphResources[GraphResourceIndex].MemberType;
const uint16 ByteOffset = GraphResources[GraphResourceIndex].MemberOffset;
if (Type == UBMT_RDG_TEXTURE ||
Type == UBMT_RDG_TEXTURE_SRV ||
Type == UBMT_RDG_TEXTURE_NON_PIXEL_SRV ||
Type == UBMT_RDG_TEXTURE_UAV ||
Type == UBMT_RDG_BUFFER_SRV ||
Type == UBMT_RDG_BUFFER_UAV)
{
const TMemoryImageArray<FShaderParameterBindings::FResourceParameter>& ResourceParameters = ShaderBindings.ResourceParameters;
const int32 ShaderResourceCount = ResourceParameters.Num();
for (; ShaderResourceIndex < ShaderResourceCount && ResourceParameters[ShaderResourceIndex].ByteOffset < ByteOffset; ++ShaderResourceIndex)
{
}
if (ShaderResourceIndex < ShaderResourceCount && ResourceParameters[ShaderResourceIndex].ByteOffset == ByteOffset)
{
continue;
}
const TMemoryImageArray<FShaderParameterBindings::FBindlessResourceParameter>& BindlessResourceParameters = ShaderBindings.BindlessResourceParameters;
const int32 BindlessResourceCount = BindlessResourceParameters.Num();
for (; BindlessResourceIndex < BindlessResourceCount && BindlessResourceParameters[BindlessResourceIndex].ByteOffset < ByteOffset; BindlessResourceIndex++)
{
}
if (BindlessResourceIndex < BindlessResourceCount && BindlessResourceParameters[BindlessResourceIndex].ByteOffset == ByteOffset)
{
continue;
}
}
else if (Type == UBMT_RDG_UNIFORM_BUFFER)
{
if (GraphUniformBufferId < ShaderBindings.GraphUniformBuffers.Num() && ByteOffset == ShaderBindings.GraphUniformBuffers[GraphUniformBufferId].ByteOffset)
{
GraphUniformBufferId++;
continue;
}
const FRDGUniformBufferBinding& UniformBuffer = *reinterpret_cast<FRDGUniformBufferBinding*>(Base + ByteOffset);
if (!UniformBuffer || UniformBuffer.IsStatic())
{
continue;
}
}
else
{
continue;
}
FRDGResourceRef* ResourcePtr = reinterpret_cast<FRDGResourceRef*>(Base + ByteOffset);
for (FRDGResourceRef ExcludeResource : ExcludeList)
{
if (*ResourcePtr == ExcludeResource)
{
continue;
}
}
*ResourcePtr = nullptr;
}
}
void ClearUnusedGraphResourcesImpl(
TArrayView<const FShaderParameterBindings*> ShaderBindingsList,
const FShaderParametersMetadata* ParametersMetadata,
void* InoutParameters,
std::initializer_list<FRDGResourceRef> ExcludeList)
{
const auto& GraphResources = ParametersMetadata->GetLayout().GraphResources;
TArray<int32, TInlineAllocator<SF_NumFrequencies>> ShaderResourceIds;
TArray<int32, TInlineAllocator<SF_NumFrequencies>> BindlessResourceIds;
TArray<int32, TInlineAllocator<SF_NumFrequencies>> GraphUniformBufferIds;
ShaderResourceIds.SetNumZeroed(ShaderBindingsList.Num());
BindlessResourceIds.SetNumZeroed(ShaderBindingsList.Num());
GraphUniformBufferIds.SetNumZeroed(ShaderBindingsList.Num());
auto Base = reinterpret_cast<uint8*>(InoutParameters);
for (int32 GraphResourceIndex = 0, GraphResourceCount = GraphResources.Num(); GraphResourceIndex < GraphResourceCount; GraphResourceIndex++)
{
EUniformBufferBaseType Type = GraphResources[GraphResourceIndex].MemberType;
uint16 ByteOffset = GraphResources[GraphResourceIndex].MemberOffset;
bool bResourceIsUsed = false;
if (Type == UBMT_RDG_TEXTURE ||
Type == UBMT_RDG_TEXTURE_SRV ||
Type == UBMT_RDG_TEXTURE_NON_PIXEL_SRV ||
Type == UBMT_RDG_TEXTURE_UAV ||
Type == UBMT_RDG_BUFFER_SRV ||
Type == UBMT_RDG_BUFFER_UAV)
{
for (int32 Index = 0; Index < ShaderBindingsList.Num(); ++Index)
{
{
const auto& ResourceParameters = ShaderBindingsList[Index]->ResourceParameters;
int32& ShaderResourceId = ShaderResourceIds[Index];
for (; ShaderResourceId < ResourceParameters.Num() && ResourceParameters[ShaderResourceId].ByteOffset < ByteOffset; ++ShaderResourceId)
{
}
bResourceIsUsed |= ShaderResourceId < ResourceParameters.Num() && ByteOffset == ResourceParameters[ShaderResourceId].ByteOffset;
}
if (!bResourceIsUsed)
{
const auto& BindlessResourceParameters = ShaderBindingsList[Index]->BindlessResourceParameters;
int32& BindlessResourceId = BindlessResourceIds[Index];
for (; BindlessResourceId < BindlessResourceParameters.Num() && BindlessResourceParameters[BindlessResourceId].ByteOffset < ByteOffset; ++BindlessResourceId)
{
}
bResourceIsUsed |= BindlessResourceId < BindlessResourceParameters.Num() && ByteOffset == BindlessResourceParameters[BindlessResourceId].ByteOffset;
}
}
}
else if (Type == UBMT_RDG_UNIFORM_BUFFER)
{
for (int32 Index = 0; Index < ShaderBindingsList.Num(); ++Index)
{
const auto& GraphUniformBuffers = ShaderBindingsList[Index]->GraphUniformBuffers;
int32& GraphUniformBufferId = GraphUniformBufferIds[Index];
for (; GraphUniformBufferId < GraphUniformBuffers.Num() && GraphUniformBuffers[GraphUniformBufferId].ByteOffset < ByteOffset; ++GraphUniformBufferId)
{
}
bResourceIsUsed |= GraphUniformBufferId < GraphUniformBuffers.Num() && ByteOffset == GraphUniformBuffers[GraphUniformBufferId].ByteOffset;
}
const FRDGUniformBufferBinding& UniformBuffer = *reinterpret_cast<const FRDGUniformBufferBinding*>(Base + ByteOffset);
if (!UniformBuffer || UniformBuffer.IsStatic())
{
continue;
}
}
else
{
// Not a resource we care about.
continue;
}
if (bResourceIsUsed)
{
continue;
}
FRDGResourceRef* ResourcePtr = reinterpret_cast<FRDGResourceRef*>(Base + ByteOffset);
for (FRDGResourceRef ExcludeResource : ExcludeList)
{
if (*ResourcePtr == ExcludeResource)
{
continue;
}
}
*ResourcePtr = nullptr;
}
}
FRDGTextureRef RegisterExternalTextureWithFallback(
FRDGBuilder& GraphBuilder,
const TRefCountPtr<IPooledRenderTarget>& ExternalPooledTexture,
const TRefCountPtr<IPooledRenderTarget>& FallbackPooledTexture)
{
ensureMsgf(FallbackPooledTexture.IsValid(), TEXT("RegisterExternalTextureWithDummyFallback() requires a valid fallback pooled texture."));
if (ExternalPooledTexture.IsValid())
{
return GraphBuilder.RegisterExternalTexture(ExternalPooledTexture);
}
else
{
return GraphBuilder.RegisterExternalTexture(FallbackPooledTexture);
}
}
RENDERCORE_API FRDGTextureMSAA CreateTextureMSAA(
FRDGBuilder& GraphBuilder,
FRDGTextureDesc Desc,
const TCHAR* NameMultisampled, const TCHAR* NameResolved,
ETextureCreateFlags ResolveFlagsToAdd)
{
const bool bForceSeparateTargetAndShaderResource = Desc.NumSamples > 1 && RHISupportsSeparateMSAAAndResolveTextures(GMaxRHIShaderPlatform);
if (LIKELY(bForceSeparateTargetAndShaderResource))
{
FRDGTextureMSAA Texture(GraphBuilder.CreateTexture(Desc, NameMultisampled));
Desc.NumSamples = 1;
ETextureCreateFlags ResolveFlags = TexCreate_ShaderResource;
if (EnumHasAnyFlags(Desc.Flags, TexCreate_DepthStencilTargetable))
{
ResolveFlags |= TexCreate_DepthStencilResolveTarget;
}
else
{
ResolveFlags |= TexCreate_ResolveTargetable;
}
ResolveFlags &= ~(TexCreate_Memoryless);
Desc.Flags = ResolveFlags | ResolveFlagsToAdd;
Texture.Resolve = GraphBuilder.CreateTexture(Desc, NameResolved);
return Texture;
}
Desc.Flags |= TexCreate_ShaderResource;
return FRDGTextureMSAA(GraphBuilder.CreateTexture(Desc, NameResolved));
}
BEGIN_SHADER_PARAMETER_STRUCT(FCopyTextureParameters, )
RDG_TEXTURE_ACCESS(Input, ERHIAccess::CopySrc)
RDG_TEXTURE_ACCESS(Output, ERHIAccess::CopyDest)
END_SHADER_PARAMETER_STRUCT()
class FDrawTexturePS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FDrawTexturePS);
SHADER_USE_PARAMETER_STRUCT(FDrawTexturePS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture)
SHADER_PARAMETER(FIntPoint, InputOffset)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FDrawTexturePS, "/Engine/Private/Tools/DrawTexture.usf", "DrawTexturePS", SF_Pixel);
void AddCopyTexturePass(
FRDGBuilder& GraphBuilder,
FRDGTextureRef InputTexture,
FRDGTextureRef OutputTexture,
const FRHICopyTextureInfo& CopyInfo)
{
if (InputTexture == OutputTexture)
{
return;
}
const FRDGTextureDesc& InputDesc = InputTexture->Desc;
const FRDGTextureDesc& OutputDesc = OutputTexture->Desc;
FCopyTextureParameters* Parameters = GraphBuilder.AllocParameters<FCopyTextureParameters>();
Parameters->Input = InputTexture;
Parameters->Output = OutputTexture;
GraphBuilder.AddPass(
RDG_EVENT_NAME("CopyTexture(%s -> %s)", InputTexture->Name, OutputTexture->Name),
Parameters,
ERDGPassFlags::Copy,
[InputTexture, OutputTexture, CopyInfo](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.CopyTexture(InputTexture->GetRHI(), OutputTexture->GetRHI(), CopyInfo);
});
}
RENDERCORE_API void AddDrawTexturePass(
FRDGBuilder& GraphBuilder,
const FGlobalShaderMap* ShaderMap,
FRDGTextureRef InputTexture,
FRDGTextureRef OutputTexture,
const FRDGDrawTextureInfo& DrawInfo)
{
if (InputTexture == OutputTexture)
{
return;
}
const FRDGTextureDesc& InputDesc = InputTexture->Desc;
const FRDGTextureDesc& OutputDesc = OutputTexture->Desc;
// Use a hardware copy if formats match.
if (InputDesc.Format == OutputDesc.Format)
{
FRHICopyTextureInfo CopyInfo;
// Translate the draw texture info into a copy info.
CopyInfo.Size = FIntVector(DrawInfo.Size.X, DrawInfo.Size.Y, 0);
CopyInfo.SourcePosition = FIntVector(DrawInfo.SourcePosition.X, DrawInfo.SourcePosition.Y, 0);
CopyInfo.DestPosition = FIntVector(DrawInfo.DestPosition.X, DrawInfo.DestPosition.Y, 0);
CopyInfo.SourceSliceIndex = DrawInfo.SourceSliceIndex;
CopyInfo.DestSliceIndex = DrawInfo.DestSliceIndex;
CopyInfo.NumSlices = DrawInfo.NumSlices;
CopyInfo.SourceMipIndex = DrawInfo.SourceMipIndex;
CopyInfo.DestMipIndex = DrawInfo.DestMipIndex;
CopyInfo.NumMips = DrawInfo.NumMips;
AddCopyTexturePass(GraphBuilder, InputTexture, OutputTexture, CopyInfo);
}
else
{
const FIntPoint DrawSize = DrawInfo.Size == FIntPoint::ZeroValue ? OutputDesc.Extent : DrawInfo.Size;
// Don't load color data if the whole texture is being overwritten.
const ERenderTargetLoadAction LoadAction = (DrawInfo.DestPosition == FIntPoint::ZeroValue && DrawSize == OutputDesc.Extent)
? ERenderTargetLoadAction::ENoAction
: ERenderTargetLoadAction::ELoad;
TShaderMapRef<FDrawTexturePS> PixelShader(ShaderMap);
for (uint32 MipIndex = 0; MipIndex < DrawInfo.NumMips; ++MipIndex)
{
const int32 SourceMipIndex = MipIndex + DrawInfo.SourceMipIndex;
const int32 DestMipIndex = MipIndex + DrawInfo.DestMipIndex;
for (uint32 SliceIndex = 0; SliceIndex < DrawInfo.NumSlices; ++SliceIndex)
{
const int32 SourceSliceIndex = SliceIndex + DrawInfo.SourceSliceIndex;
const int32 DestSliceIndex = SliceIndex + DrawInfo.DestSliceIndex;
FRDGTextureSRVDesc SRVDesc = FRDGTextureSRVDesc::CreateForMipLevel(InputTexture, SourceMipIndex);
SRVDesc.FirstArraySlice = SourceSliceIndex;
auto* PassParameters = GraphBuilder.AllocParameters<FDrawTexturePS::FParameters>();
PassParameters->InputTexture = GraphBuilder.CreateSRV(SRVDesc);
PassParameters->InputOffset = DrawInfo.SourcePosition;
PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputTexture, LoadAction, DestMipIndex, DestSliceIndex);
const FIntRect ViewRect(DrawInfo.DestPosition, DrawInfo.DestPosition + DrawSize);
FPixelShaderUtils::AddFullscreenPass(
GraphBuilder,
ShaderMap,
RDG_EVENT_NAME("DrawTexture ([%s, Mip: %d, Slice: %d] -> [%s, Mip: %d, Slice: %d])", InputTexture->Name, SourceMipIndex, SourceSliceIndex, OutputTexture->Name, DestMipIndex, DestSliceIndex),
PixelShader,
PassParameters,
ViewRect
);
}
}
}
}
BEGIN_SHADER_PARAMETER_STRUCT(FCopyBufferParameters, )
RDG_BUFFER_ACCESS(SrcBuffer, ERHIAccess::CopySrc)
RDG_BUFFER_ACCESS(DstBuffer, ERHIAccess::CopyDest)
END_SHADER_PARAMETER_STRUCT()
void AddCopyBufferPass(FRDGBuilder& GraphBuilder, FRDGBufferRef DstBuffer, uint64 DstOffset, FRDGBufferRef SrcBuffer, uint64 SrcOffset, uint64 NumBytes)
{
check(SrcBuffer);
check(DstBuffer);
FCopyBufferParameters* Parameters = GraphBuilder.AllocParameters<FCopyBufferParameters>();
Parameters->SrcBuffer = SrcBuffer;
Parameters->DstBuffer = DstBuffer;
GraphBuilder.AddPass(
RDG_EVENT_NAME("CopyBuffer(%s Size=%ubytes)", SrcBuffer->Name, SrcBuffer->Desc.GetSize()),
Parameters,
ERDGPassFlags::Copy,
[&Parameters, SrcBuffer, DstBuffer, SrcOffset, DstOffset, NumBytes](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.CopyBufferRegion(DstBuffer->GetRHI(), DstOffset, SrcBuffer->GetRHI(), SrcOffset, NumBytes);
});
}
void AddCopyBufferPass(FRDGBuilder& GraphBuilder, FRDGBufferRef DstBuffer, FRDGBufferRef SrcBuffer)
{
check(SrcBuffer);
check(DstBuffer);
const uint64 NumBytes = SrcBuffer->Desc.NumElements * SrcBuffer->Desc.BytesPerElement;
AddCopyBufferPass(GraphBuilder, DstBuffer, 0, SrcBuffer, 0, NumBytes);
}
BEGIN_SHADER_PARAMETER_STRUCT(FClearBufferUAVParameters, )
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, BufferUAV)
END_SHADER_PARAMETER_STRUCT()
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGBufferUAVRef BufferUAV, uint32 Value, ERDGPassFlags ComputePassFlags)
{
check(BufferUAV);
FClearBufferUAVParameters* Parameters = GraphBuilder.AllocParameters<FClearBufferUAVParameters>();
Parameters->BufferUAV = BufferUAV;
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearBuffer(%s Size=%ubytes)", BufferUAV->GetParent()->Name, BufferUAV->GetParent()->Desc.GetSize()),
Parameters,
ComputePassFlags,
[&Parameters, BufferUAV, Value](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
{
RHICmdList.ClearUAVUint(BufferUAV->GetRHI(), FUintVector4(Value, Value, Value, Value));
BufferUAV->MarkResourceAsUsed();
});
}
void AddClearUAVFloatPass(FRDGBuilder& GraphBuilder, FRDGBufferUAVRef BufferUAV, float Value, ERDGPassFlags ComputePassFlags)
{
FClearBufferUAVParameters* Parameters = GraphBuilder.AllocParameters<FClearBufferUAVParameters>();
Parameters->BufferUAV = BufferUAV;
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearBuffer(%s Size=%ubytes)", BufferUAV->GetParent()->Name, BufferUAV->GetParent()->Desc.GetSize()),
Parameters,
ComputePassFlags,
[&Parameters, BufferUAV, Value](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
{
RHICmdList.ClearUAVFloat(BufferUAV->GetRHI(), FVector4f(Value, Value, Value, Value));
BufferUAV->MarkResourceAsUsed();
});
}
BEGIN_SHADER_PARAMETER_STRUCT(FClearTextureUAVParameters, )
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, TextureUAV)
END_SHADER_PARAMETER_STRUCT()
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FUintVector4& ClearValues, ERDGPassFlags ComputePassFlags)
{
check(TextureUAV);
FClearTextureUAVParameters* Parameters = GraphBuilder.AllocParameters<FClearTextureUAVParameters>();
Parameters->TextureUAV = TextureUAV;
FRDGTextureRef Texture = TextureUAV->GetParent();
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearTextureUint(%s %s %dx%d Mip=%d)",
Texture->Name,
GPixelFormats[Texture->Desc.Format].Name,
Texture->Desc.Extent.X, Texture->Desc.Extent.Y,
int32(TextureUAV->Desc.MipLevel)),
Parameters,
ComputePassFlags,
[&Parameters, TextureUAV, ClearValues](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
{
const FRDGTextureDesc& LocalTextureDesc = TextureUAV->GetParent()->Desc;
FRHIUnorderedAccessView* RHITextureUAV = TextureUAV->GetRHI();
RHICmdList.ClearUAVUint(RHITextureUAV, ClearValues);
TextureUAV->MarkResourceAsUsed();
});
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector4f& ClearValues, ERDGPassFlags ComputePassFlags)
{
check(TextureUAV);
FClearTextureUAVParameters* Parameters = GraphBuilder.AllocParameters<FClearTextureUAVParameters>();
Parameters->TextureUAV = TextureUAV;
const FRDGTextureDesc& TextureDesc = TextureUAV->GetParent()->Desc;
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearTextureFloat(%s) %dx%d", TextureUAV->GetParent()->Name, TextureDesc.Extent.X, TextureDesc.Extent.Y),
Parameters,
ComputePassFlags,
[&Parameters, TextureUAV, ClearValues](FRDGAsyncTask, FRHIComputeCommandList& RHICmdList)
{
const FRDGTextureDesc& LocalTextureDesc = TextureUAV->GetParent()->Desc;
FRHIUnorderedAccessView* RHITextureUAV = TextureUAV->GetRHI();
RHICmdList.ClearUAVFloat(RHITextureUAV, ClearValues);
TextureUAV->MarkResourceAsUsed();
});
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const uint32(&ClearValues)[4], ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, FUintVector4(ClearValues[0], ClearValues[1], ClearValues[2], ClearValues[3]), ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const float(&ClearValues)[4], ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(ClearValues[0], ClearValues[1], ClearValues[2], ClearValues[3]), ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FLinearColor& ClearColor, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(ClearColor.R, ClearColor.G, ClearColor.B, ClearColor.A), ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, uint32 Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, { Value, Value , Value , Value }, ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, float Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, { Value, Value , Value , Value }, ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector& Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, { (float)Value.X, (float)Value.Y , (float)Value.Z , 0.f }, ComputePassFlags); // LWC_TODO: Precision loss?
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FIntPoint& Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, { uint32(Value.X), uint32(Value.Y), 0u, 0u }, ComputePassFlags);
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector2D& Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, { (float)Value.X,(float)Value.Y , 0.f, 0.f }, ComputePassFlags); // LWC_TODO: Precision loss?
}
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector4d& Value, ERDGPassFlags ComputePassFlags)
{
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(Value), ComputePassFlags); // LWC_TODO: Precision loss?
}
class FClearUAVRectsPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FClearUAVRectsPS);
SHADER_USE_PARAMETER_STRUCT(FClearUAVRectsPS, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FUintVector4, ClearValue)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, ClearResource)
END_SHADER_PARAMETER_STRUCT()
using FPermutationDomain = TShaderPermutationDomain<>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
int32 ResourceType = RHIGetPreferredClearUAVRectPSResourceType(Parameters.Platform);
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("ENABLE_CLEAR_VALUE"), 1);
OutEnvironment.SetDefine(TEXT("RESOURCE_TYPE"), ResourceType);
OutEnvironment.SetDefine(TEXT("VALUE_TYPE"), TEXT("uint4"));
}
};
IMPLEMENT_GLOBAL_SHADER(FClearUAVRectsPS, "/Engine/Private/ClearReplacementShaders.usf", "ClearTextureRWPS", SF_Pixel);
BEGIN_SHADER_PARAMETER_STRUCT(FClearUAVRectsParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FPixelShaderUtils::FRasterizeToRectsVS::FParameters, VS)
SHADER_PARAMETER_STRUCT_INCLUDE(FClearUAVRectsPS::FParameters, PS)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
void AddClearUAVPass(FRDGBuilder& GraphBuilder, ERHIFeatureLevel::Type FeatureLevel, FRDGTextureUAVRef TextureUAV, const uint32(&ClearValues)[4], FRDGBufferSRVRef RectCoordBufferSRV, uint32 NumRects)
{
if (NumRects == 0)
{
AddClearUAVPass(GraphBuilder, TextureUAV, ClearValues);
return;
}
check(TextureUAV && RectCoordBufferSRV);
const FRDGTextureRef Texture = TextureUAV->GetParent();
const FIntPoint TextureSize = Texture->Desc.Extent;
// Create a R32G32 view of the R64 instead of adding a permutation to the clear shader
if (Texture->Desc.Format == PF_R64_UINT)
{
TextureUAV = GraphBuilder.CreateUAV(Texture, ERDGUnorderedAccessViewFlags::None, PF_R32G32_UINT);
}
FClearUAVRectsParameters* PassParameters = GraphBuilder.AllocParameters<FClearUAVRectsParameters>();
PassParameters->PS.ClearValue.X = ClearValues[0];
PassParameters->PS.ClearValue.Y = ClearValues[1];
PassParameters->PS.ClearValue.Z = ClearValues[2];
PassParameters->PS.ClearValue.W = ClearValues[3];
PassParameters->PS.ClearResource = TextureUAV;
auto* ShaderMap = GetGlobalShaderMap(FeatureLevel);
auto PixelShader = ShaderMap->GetShader<FClearUAVRectsPS>();
const ERDGPassFlags AdditionalRenderPassFlags = (PassParameters->RenderTargets.GetActiveCount() == 0) ? ERDGPassFlags::SkipRenderPass : ERDGPassFlags::None;
FPixelShaderUtils::AddRasterizeToRectsPass<FClearUAVRectsPS>(GraphBuilder,
ShaderMap,
RDG_EVENT_NAME("ClearTextureRects(%s %s %dx%d Mip=%d)",
Texture->Name,
GPixelFormats[Texture->Desc.Format].Name,
Texture->Desc.Extent.X, Texture->Desc.Extent.Y,
int32(TextureUAV->Desc.MipLevel)),
PixelShader,
PassParameters,
TextureSize,
RectCoordBufferSRV,
NumRects,
/*BlendState*/ nullptr,
/*RasterizerState*/ nullptr,
/*DepthStencilState*/ nullptr,
/*StencilRef*/ 0,
/*TextureSize*/ TextureSize,
/*RectUVBufferSRV*/ nullptr,
/*DownsampleFactor*/ 1,
AdditionalRenderPassFlags);
}
void AddClearRenderTargetPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture)
{
// Single mip, single slice, same clear color as what is specified in the render target :
AddClearRenderTargetPass(GraphBuilder, Texture, FRDGTextureClearInfo());
}
void AddClearRenderTargetPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture, const FLinearColor& ClearColor)
{
// Single mip, single slice, custom clear color :
FRDGTextureClearInfo TextureClearInfo;
TextureClearInfo.ClearColor = ClearColor;
AddClearRenderTargetPass(GraphBuilder, Texture, TextureClearInfo);
}
void AddClearRenderTargetPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture, const FLinearColor& ClearColor, FIntRect Viewport)
{
// Single mip, single slice, custom viewport, custom clear color :
FRDGTextureClearInfo TextureClearInfo;
TextureClearInfo.ClearColor = ClearColor;
TextureClearInfo.Viewport = Viewport;
AddClearRenderTargetPass(GraphBuilder, Texture, TextureClearInfo);
}
void AddClearRenderTargetPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture, const FRDGTextureClearInfo& TextureClearInfo)
{
check(Texture);
bool bUseCustomViewport = (TextureClearInfo.Viewport.Area() > 0);
FLinearColor ClearColor = TextureClearInfo.ClearColor.IsSet() ? TextureClearInfo.ClearColor.GetValue() : Texture->Desc.ClearValue.GetClearColor();
uint16 TextureNumSlicesOrDepth = Texture->Desc.IsTexture3D() ? Texture->Desc.Depth : Texture->Desc.ArraySize;
checkf((TextureClearInfo.FirstMipIndex < Texture->Desc.NumMips) && ((TextureClearInfo.FirstMipIndex + TextureClearInfo.NumMips) <= Texture->Desc.NumMips),
TEXT("Invalid mip range [%d, %d] for texture %s (%d mips)"), TextureClearInfo.FirstMipIndex, TextureClearInfo.FirstMipIndex + TextureClearInfo.NumMips - 1, Texture->Name, Texture->Desc.NumMips);
checkf(((TextureClearInfo.FirstSliceIndex == 0) && (TextureClearInfo.NumSlices == 1)) || (Texture->Desc.IsTextureArray() && (EnumHasAnyFlags(Texture->Desc.Flags, ETextureCreateFlags::TargetArraySlicesIndependently) || GRHISupportsBindingTexArrayPerSlice)),
TEXT("Per-slice clear (outside of slice 0, i.e. clearing any other slice than the first one) is only supported on 2DArray at the moment and ETextureCreateFlags::TargetArraySlicesIndependently must be passed when creating the texture (texture %s)."), Texture->Name);
checkf((TextureClearInfo.FirstSliceIndex < TextureNumSlicesOrDepth) && ((TextureClearInfo.FirstSliceIndex + TextureClearInfo.NumSlices) <= TextureNumSlicesOrDepth),
TEXT("Invalid slice range [%d, %d] for texture %s (%d slices)"), TextureClearInfo.FirstSliceIndex, TextureClearInfo.FirstSliceIndex + TextureClearInfo.NumSlices - 1, Texture->Name, TextureNumSlicesOrDepth);
// Use clear action if no viewport specified and clear color is not passed or matches the fast clear color :
if (!bUseCustomViewport
&& (Texture->Desc.ClearValue.ColorBinding == EClearBinding::EColorBound)
&& (Texture->Desc.ClearValue.GetClearColor() == ClearColor))
{
for (uint32 SliceIndex = 0; SliceIndex < TextureClearInfo.NumSlices; ++SliceIndex)
{
uint16 CurrentSliceIndex = IntCastChecked<uint16>(TextureClearInfo.FirstSliceIndex + SliceIndex);
for (uint32 MipIndex = 0; MipIndex < TextureClearInfo.NumMips; ++MipIndex)
{
uint8 CurrentMipIndex = IntCastChecked<uint8>(TextureClearInfo.FirstMipIndex + MipIndex);
FRenderTargetParameters* Parameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
Parameters->RenderTargets[0] = FRenderTargetBinding(Texture, ERenderTargetLoadAction::EClear, CurrentMipIndex, CurrentSliceIndex);
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearRenderTarget(%s, slice %d, mip %d) %dx%d ClearAction", Texture->Name, CurrentSliceIndex, CurrentMipIndex, Texture->Desc.Extent.X, Texture->Desc.Extent.Y),
Parameters,
ERDGPassFlags::Raster,
[](FRDGAsyncTask, FRHICommandList& RHICmdList) {});
}
}
}
else
{
FIntRect OriginalViewport = bUseCustomViewport ? TextureClearInfo.Viewport : FIntRect(FIntPoint::ZeroValue, Texture->Desc.Extent);
checkf((OriginalViewport.Max.X <= Texture->Desc.Extent.X) && (OriginalViewport.Max.Y <= Texture->Desc.Extent.Y), TEXT("Invalid custom viewport ((%d, %d) - (%d, %d)) for texture %s (size (%d, %d))"),
OriginalViewport.Min.X, OriginalViewport.Min.Y, OriginalViewport.Max.X, OriginalViewport.Max.Y, Texture->Name, Texture->Desc.Extent.X, Texture->Desc.Extent.Y);
for (uint32 SliceIndex = 0; SliceIndex < TextureClearInfo.NumSlices; ++SliceIndex)
{
uint16 CurrentSliceIndex = IntCastChecked<uint16>(TextureClearInfo.FirstSliceIndex + SliceIndex);
for (uint32 MipIndex = 0; MipIndex < TextureClearInfo.NumMips; ++MipIndex)
{
FIntRect CurrentViewport(
(uint32)OriginalViewport.Min.X >> MipIndex,
(uint32)OriginalViewport.Min.Y >> MipIndex,
FMath::Max(1u, (uint32)OriginalViewport.Max.X >> MipIndex),
FMath::Max(1u, (uint32)OriginalViewport.Max.Y >> MipIndex));
uint8 CurrentMipIndex = IntCastChecked<uint8>(TextureClearInfo.FirstMipIndex + MipIndex);
if (CurrentViewport.Area() > 0)
{
FRenderTargetParameters* Parameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
Parameters->RenderTargets[0] = FRenderTargetBinding(Texture, ERenderTargetLoadAction::ENoAction, CurrentMipIndex, CurrentSliceIndex);
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearRenderTarget(%s, slice %d, mip %d) [(%d, %d), (%d, %d)] ClearQuad", Texture->Name, CurrentSliceIndex, CurrentMipIndex, CurrentViewport.Min.X, CurrentViewport.Min.Y, CurrentViewport.Max.X, CurrentViewport.Max.Y),
Parameters,
ERDGPassFlags::Raster,
[Parameters, ClearColor, CurrentViewport](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.SetViewport((float)CurrentViewport.Min.X, (float)CurrentViewport.Min.Y, 0.0f, (float)CurrentViewport.Max.X, (float)CurrentViewport.Max.Y, 1.0f);
DrawClearQuad(RHICmdList, ClearColor);
});
CurrentViewport = CurrentViewport / 2;
}
}
}
}
}
void AddClearDepthStencilPass(
FRDGBuilder& GraphBuilder,
FRDGTextureRef Texture,
bool bClearDepth,
float Depth,
bool bClearStencil,
uint8 Stencil)
{
check(Texture);
FExclusiveDepthStencil ExclusiveDepthStencil;
ERenderTargetLoadAction DepthLoadAction = ERenderTargetLoadAction::ELoad;
ERenderTargetLoadAction StencilLoadAction = ERenderTargetLoadAction::ENoAction;
const bool bHasStencil = Texture->Desc.Format == PF_DepthStencil;
// We can't clear stencil if we don't have it.
bClearStencil &= bHasStencil;
if (bClearDepth)
{
ExclusiveDepthStencil.SetDepthWrite();
DepthLoadAction = ERenderTargetLoadAction::ENoAction;
}
if (bHasStencil)
{
if (bClearStencil)
{
ExclusiveDepthStencil.SetStencilWrite();
StencilLoadAction = ERenderTargetLoadAction::ENoAction;
}
else
{
// Preserve stencil contents.
StencilLoadAction = ERenderTargetLoadAction::ELoad;
}
}
FRenderTargetParameters* Parameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
Parameters->RenderTargets.DepthStencil = FDepthStencilBinding(Texture, DepthLoadAction, StencilLoadAction, ExclusiveDepthStencil);
GraphBuilder.AddPass(
RDG_EVENT_NAME("ClearDepthStencil(%s) %dx%d", Texture->Name, Texture->Desc.Extent.X, Texture->Desc.Extent.Y),
Parameters,
ERDGPassFlags::Raster,
[Parameters, bClearDepth, Depth, bClearStencil, Stencil](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
DrawClearQuad(RHICmdList, false, FLinearColor(), bClearDepth, Depth, bClearStencil, Stencil);
});
}
void AddClearDepthStencilPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture, ERenderTargetLoadAction DepthLoadAction, ERenderTargetLoadAction StencilLoadAction)
{
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(Texture, DepthLoadAction, StencilLoadAction, FExclusiveDepthStencil::DepthWrite_StencilWrite);
GraphBuilder.AddPass(RDG_EVENT_NAME("ClearDepthStencil (%s)", Texture->Name), PassParameters, ERDGPassFlags::Raster, [](FRDGAsyncTask, FRHICommandList&) {});
}
void AddClearStencilPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture)
{
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(Texture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::EClear, FExclusiveDepthStencil::DepthRead_StencilWrite);
GraphBuilder.AddPass(RDG_EVENT_NAME("ClearStencil (%s)", Texture->Name), PassParameters, ERDGPassFlags::Raster, [](FRDGAsyncTask, FRHICommandList&) {});
}
void AddResummarizeHTilePass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture)
{
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
const bool bHasStencil = Texture->Desc.Format == PF_DepthStencil;
PassParameters->RenderTargets.DepthStencil = bHasStencil ?
FDepthStencilBinding(Texture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite) :
FDepthStencilBinding(Texture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ENoAction, FExclusiveDepthStencil::DepthWrite_StencilNop);
GraphBuilder.AddPass(RDG_EVENT_NAME("ResummarizeHTile (%s)", Texture->Name), PassParameters, ERDGPassFlags::Raster,
[Texture](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
RHICmdList.ResummarizeHTile(static_cast<FRHITexture*>(Texture->GetRHI()));
});
}
BEGIN_SHADER_PARAMETER_STRUCT(FEnqueueCopyTexturePass, )
RDG_TEXTURE_ACCESS(Texture, ERHIAccess::CopySrc)
END_SHADER_PARAMETER_STRUCT()
void AddEnqueueCopyPass(FRDGBuilder& GraphBuilder, FRHIGPUTextureReadback* Readback, FRDGTextureRef SourceTexture, FResolveRect Rect)
{
FEnqueueCopyTexturePass* PassParameters = GraphBuilder.AllocParameters<FEnqueueCopyTexturePass>();
PassParameters->Texture = SourceTexture;
GraphBuilder.AddPass(
RDG_EVENT_NAME("EnqueueCopy(%s)", SourceTexture->Name),
PassParameters,
ERDGPassFlags::Readback,
[Readback, SourceTexture, Rect](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
Readback->EnqueueCopy(RHICmdList, SourceTexture->GetRHI(), Rect);
});
}
BEGIN_SHADER_PARAMETER_STRUCT(FEnqueueCopyBufferPass, )
RDG_BUFFER_ACCESS(Buffer, ERHIAccess::CopySrc)
END_SHADER_PARAMETER_STRUCT()
void AddEnqueueCopyPass(FRDGBuilder& GraphBuilder, FRHIGPUBufferReadback* Readback, FRDGBufferRef SourceBuffer, uint32 NumBytes)
{
FEnqueueCopyBufferPass* PassParameters = GraphBuilder.AllocParameters<FEnqueueCopyBufferPass>();
PassParameters->Buffer = SourceBuffer;
GraphBuilder.AddPass(
RDG_EVENT_NAME("EnqueueCopy(%s)", SourceBuffer->Name),
PassParameters,
ERDGPassFlags::Readback,
[Readback, SourceBuffer, NumBytes](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
Readback->EnqueueCopy(RHICmdList, SourceBuffer->GetRHI(), NumBytes);
});
}
class FInitIndirectArgs1DCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FInitIndirectArgs1DCS);
SHADER_USE_PARAMETER_STRUCT(FInitIndirectArgs1DCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint >, InputCountBuffer)
SHADER_PARAMETER(uint32, Multiplier)
SHADER_PARAMETER(uint32, Divisor)
SHADER_PARAMETER(uint32, InputCountOffset)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer< uint >, IndirectDispatchArgsOut)
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FInitIndirectArgs1DCS, "/Engine/Private/Tools/SetupIndirectArgs.usf", "InitIndirectArgs1DCS", SF_Compute);
FRDGBufferRef FComputeShaderUtils::AddIndirectArgsSetupCsPass1D(FRDGBuilder& GraphBuilder, ERHIFeatureLevel::Type FeatureLevel, FRDGBuffer* InputCountBuffer, const TCHAR* OutputBufferName, uint32 Divisor, uint32 InputCountOffset, uint32 Multiplier)
{
// 1. Add setup pass
FRDGBufferRef IndirectArgsBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(), OutputBufferName);
{
FInitIndirectArgs1DCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FInitIndirectArgs1DCS::FParameters>();
PassParameters->InputCountBuffer = GraphBuilder.CreateSRV(InputCountBuffer);
PassParameters->Multiplier = Multiplier;
PassParameters->Divisor = Divisor;
PassParameters->InputCountOffset = InputCountOffset;
PassParameters->IndirectDispatchArgsOut = GraphBuilder.CreateUAV(IndirectArgsBuffer, PF_R32_UINT);
auto ComputeShader = GetGlobalShaderMap(FeatureLevel)->GetShader<FInitIndirectArgs1DCS>();
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("InitIndirectArgs1D"),
ComputeShader,
PassParameters,
FIntVector(1, 1, 1)
);
}
return IndirectArgsBuffer;
}
FRDGBufferRef CreateStructuredBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
uint32 BytesPerElement,
uint32 NumElements,
const void* InitialData,
uint64 InitialDataSize,
ERDGInitialDataFlags InitialDataFlags)
{
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(BytesPerElement, NumElements), Name);
GraphBuilder.QueueBufferUpload(Buffer, InitialData, InitialDataSize, InitialDataFlags);
return Buffer;
}
FRDGBufferRef CreateStructuredBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
uint32 BytesPerElement,
FRDGBufferNumElementsCallback&& NumElementsCallback,
FRDGBufferInitialDataCallback&& InitialDataCallback,
FRDGBufferInitialDataSizeCallback&& InitialDataSizeCallback)
{
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(BytesPerElement, 1), Name, MoveTemp(NumElementsCallback));
GraphBuilder.QueueBufferUpload(Buffer, MoveTemp(InitialDataCallback), MoveTemp(InitialDataSizeCallback));
return Buffer;
}
FRDGBufferRef CreateByteAddressBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
uint32 NumBytes,
const void* InitialData,
uint64 InitialDataSize,
ERDGInitialDataFlags InitialDataFlags)
{
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateByteAddressDesc(NumBytes), Name);
GraphBuilder.QueueBufferUpload(Buffer, InitialData, InitialDataSize, InitialDataFlags);
return Buffer;
}
FRDGBufferRef CreateByteAddressBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
FRDGBufferNumElementsCallback&& NumElementsCallback,
FRDGBufferInitialDataCallback&& InitialDataCallback,
FRDGBufferInitialDataSizeCallback&& InitialDataSizeCallback)
{
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateByteAddressDesc(4), Name, MoveTemp(NumElementsCallback));
GraphBuilder.QueueBufferUpload(Buffer, MoveTemp(InitialDataCallback), MoveTemp(InitialDataSizeCallback));
return Buffer;
}
FRDGBufferRef CreateUploadBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
uint32 BytesPerElement,
uint32 NumElements,
const void* InitialData,
uint64 InitialDataSize,
ERDGInitialDataFlags InitialDataFlags)
{
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateUploadDesc(BytesPerElement, NumElements), Name);
if (InitialData != nullptr && InitialDataSize > 0)
{
GraphBuilder.QueueBufferUpload(Buffer, InitialData, InitialDataSize, InitialDataFlags);
}
return Buffer;
}
FRDGBufferRef CreateVertexBuffer(
FRDGBuilder& GraphBuilder,
const TCHAR* Name,
const FRDGBufferDesc& Desc,
const void* InitialData,
uint64 InitialDataSize,
ERDGInitialDataFlags InitialDataFlags)
{
checkf(Name!=nullptr, TEXT("Buffer must have a name."));
checkf(EnumHasAnyFlags(Desc.Usage, EBufferUsageFlags::VertexBuffer), TEXT("CreateVertexBuffer called with an FRDGBufferDesc underlying type that is not 'VertexBuffer'. Buffer: %s"), Name);
FRDGBufferRef Buffer = GraphBuilder.CreateBuffer(Desc, Name);
GraphBuilder.QueueBufferUpload(Buffer, InitialData, InitialDataSize, InitialDataFlags);
return Buffer;
}
void FRDGExternalAccessQueue::Submit(FRDGBuilder& GraphBuilder)
{
for (FResource Resource : Resources)
{
GraphBuilder.UseExternalAccessMode(Resource.Resource, Resource.Access, Resource.Pipelines);
}
Resources.Empty();
}
bool AllocatePooledBuffer(
const FRDGBufferDesc& Desc,
TRefCountPtr<FRDGPooledBuffer>& Out,
const TCHAR* Name,
ERDGPooledBufferAlignment Alignment)
{
if (Out && Out->Desc == Desc)
{
// Kept current allocation.
return false;
}
// New allocation.
Out = GRenderGraphResourcePool.FindFreeBuffer(Desc, Name, Alignment);
return true;
}
TRefCountPtr<FRDGPooledBuffer> AllocatePooledBuffer(const FRDGBufferDesc& Desc, const TCHAR* Name, ERDGPooledBufferAlignment Alignment)
{
return GRenderGraphResourcePool.FindFreeBuffer(Desc, Name, Alignment);
}
bool AllocatePooledTexture(const FRDGTextureDesc& Desc, TRefCountPtr<IPooledRenderTarget>& Out, const TCHAR* Name)
{
return GRenderTargetPool.FindFreeElement(Desc, Out, Name);
}
TRefCountPtr<IPooledRenderTarget> AllocatePooledTexture(const FRDGTextureDesc& Desc, const TCHAR* Name)
{
return GRenderTargetPool.FindFreeElement(Desc, Name);
}
#if ENABLE_LOW_LEVEL_MEM_TRACKER || UE_MEMORY_TRACE_ENABLED
TRefCountPtr<FRDGPooledBuffer> AllocatePooledBufferCurrentLLMTag(FRHICommandListBase& RHICmdList, const FRDGBufferDesc& Desc, const TCHAR* Name, ERDGPooledBufferAlignment Alignment)
{
TRefCountPtr<FRDGPooledBuffer> RDGPooledBuffer = AllocatePooledBuffer(Desc, Name, Alignment);
if (RDGPooledBuffer && RDGPooledBuffer->GetRHI())
{
RHICmdList.UpdateAllocationTags(RDGPooledBuffer->GetRHI());
}
return RDGPooledBuffer;
}
#endif