You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#preflight 62756de8d8373707f22a6144 #rb christopher.waters [CL 20082899 by zach bethel in ue5-main branch]
1073 lines
40 KiB
C++
1073 lines
40 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "RenderGraphUtils.h"
|
|
#include "ClearQuad.h"
|
|
#include "ClearReplacementShaders.h"
|
|
#include "ShaderParameterUtils.h"
|
|
#include "RenderTargetPool.h"
|
|
#include <initializer_list>
|
|
#include "GlobalShader.h"
|
|
#include "PixelShaderUtils.h"
|
|
#include "RenderGraphResourcePool.h"
|
|
#include "RHIGPUReadback.h"
|
|
|
|
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 GraphUniformBufferId = 0;
|
|
auto 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_UAV ||
|
|
Type == UBMT_RDG_BUFFER_SRV ||
|
|
Type == UBMT_RDG_BUFFER_UAV)
|
|
{
|
|
const auto& ResourceParameters = ShaderBindings.ResourceParameters;
|
|
const int32 ShaderResourceCount = ResourceParameters.Num();
|
|
for (; ShaderResourceIndex < ShaderResourceCount && ResourceParameters[ShaderResourceIndex].ByteOffset < ByteOffset; ++ShaderResourceIndex)
|
|
{
|
|
}
|
|
|
|
if (ShaderResourceIndex < ShaderResourceCount && ResourceParameters[ShaderResourceIndex].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>> GraphUniformBufferIds;
|
|
ShaderResourceIds.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_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;
|
|
}
|
|
}
|
|
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* Name,
|
|
ETextureCreateFlags ResolveFlagsToAdd)
|
|
{
|
|
FRDGTextureMSAA Texture(GraphBuilder.CreateTexture(Desc, Name));
|
|
|
|
if (Desc.NumSamples > 1)
|
|
{
|
|
Desc.NumSamples = 1;
|
|
ETextureCreateFlags ResolveFlags = TexCreate_ShaderResource;
|
|
if (EnumHasAnyFlags(Desc.Flags, TexCreate_DepthStencilTargetable))
|
|
{
|
|
ResolveFlags |= TexCreate_DepthStencilResolveTarget;
|
|
}
|
|
else
|
|
{
|
|
ResolveFlags |= TexCreate_ResolveTargetable;
|
|
}
|
|
Desc.Flags = ResolveFlags | ResolveFlagsToAdd;
|
|
Texture.Resolve = GraphBuilder.CreateTexture(Desc, Name);
|
|
}
|
|
|
|
return Texture;
|
|
}
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FCopyTextureParameters, )
|
|
RDG_TEXTURE_ACCESS(Input, ERHIAccess::CopySrc)
|
|
RDG_TEXTURE_ACCESS(Output, ERHIAccess::CopyDest)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
class RENDERCORE_API 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;
|
|
checkf(InputDesc.Format == OutputDesc.Format, TEXT("This method does not support format conversion."));
|
|
|
|
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](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::Create(InputTexture);
|
|
SRVDesc.FirstArraySlice = SourceSliceIndex;
|
|
SRVDesc.NumArraySlices = 1;
|
|
SRVDesc.MipLevel = SourceMipIndex;
|
|
SRVDesc.NumMipLevels = 1;
|
|
|
|
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(FCopyToResolveTargetParameters, )
|
|
RDG_TEXTURE_ACCESS_DYNAMIC(Input)
|
|
RDG_TEXTURE_ACCESS_DYNAMIC(Output)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
void AddCopyToResolveTargetPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef OutputTexture,
|
|
const FResolveParams& ResolveParams)
|
|
{
|
|
check(InputTexture && OutputTexture);
|
|
|
|
if (InputTexture == OutputTexture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ERHIAccess AccessSource = ERHIAccess::ResolveSrc;
|
|
ERHIAccess AccessDest = ERHIAccess::ResolveDst;
|
|
|
|
// This might also just be a copy.
|
|
if (InputTexture->Desc.NumSamples == OutputTexture->Desc.NumSamples)
|
|
{
|
|
AccessSource = ERHIAccess::CopySrc;
|
|
AccessDest = ERHIAccess::CopyDest;
|
|
}
|
|
|
|
FCopyToResolveTargetParameters* Parameters = GraphBuilder.AllocParameters<FCopyToResolveTargetParameters>();
|
|
Parameters->Input = FRDGTextureAccess(InputTexture, AccessSource);
|
|
Parameters->Output = FRDGTextureAccess(OutputTexture, AccessDest);
|
|
|
|
FResolveParams LocalResolveParams = ResolveParams;
|
|
LocalResolveParams.SourceAccessFinal = AccessSource;
|
|
LocalResolveParams.DestAccessFinal = AccessDest;
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("CopyToResolveTarget(%s -> %s)", InputTexture->Name, OutputTexture->Name),
|
|
Parameters,
|
|
ERDGPassFlags::Copy | ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
|
|
[InputTexture, OutputTexture, LocalResolveParams](FRHICommandList& RHICmdList)
|
|
{
|
|
RHICmdList.CopyToResolveTarget(InputTexture->GetRHI(), OutputTexture->GetRHI(), LocalResolveParams);
|
|
});
|
|
}
|
|
|
|
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, FRDGBufferRef SrcBuffer)
|
|
{
|
|
check(SrcBuffer);
|
|
check(DstBuffer);
|
|
|
|
FCopyBufferParameters* Parameters = GraphBuilder.AllocParameters<FCopyBufferParameters>();
|
|
Parameters->SrcBuffer = SrcBuffer;
|
|
Parameters->DstBuffer = DstBuffer;
|
|
const uint64 NumBytes = Parameters->SrcBuffer->Desc.NumElements * Parameters->SrcBuffer->Desc.BytesPerElement;
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("CopyBuffer(%s Size=%ubytes)", SrcBuffer->Name, SrcBuffer->Desc.GetSize()),
|
|
Parameters,
|
|
ERDGPassFlags::Copy,
|
|
[&Parameters, SrcBuffer, DstBuffer, NumBytes](FRHICommandList& RHICmdList)
|
|
{
|
|
RHICmdList.CopyBufferRegion(DstBuffer->GetRHI(), 0, SrcBuffer->GetRHI(), 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)
|
|
{
|
|
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,
|
|
ERDGPassFlags::Compute,
|
|
[&Parameters, BufferUAV, Value](FRHIComputeCommandList& RHICmdList)
|
|
{
|
|
RHICmdList.ClearUAVUint(BufferUAV->GetRHI(), FUintVector4(Value, Value, Value, Value));
|
|
BufferUAV->MarkResourceAsUsed();
|
|
});
|
|
}
|
|
|
|
void AddClearUAVFloatPass(FRDGBuilder& GraphBuilder, FRDGBufferUAVRef BufferUAV, float Value)
|
|
{
|
|
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,
|
|
ERDGPassFlags::Compute,
|
|
[&Parameters, BufferUAV, Value](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)
|
|
{
|
|
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,
|
|
ERDGPassFlags::Compute,
|
|
[&Parameters, TextureUAV, ClearValues](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)
|
|
{
|
|
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,
|
|
ERDGPassFlags::Compute,
|
|
[&Parameters, TextureUAV, ClearValues](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])
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, FUintVector4(ClearValues[0], ClearValues[1], ClearValues[2], ClearValues[3]));
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const float(&ClearValues)[4])
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(ClearValues[0], ClearValues[1], ClearValues[2], ClearValues[3]));
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FLinearColor& ClearColor)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(ClearColor.R, ClearColor.G, ClearColor.B, ClearColor.A));
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, uint32 Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, { Value, Value , Value , Value });
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, float Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, { Value, Value , Value , Value });
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector& Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, { (float)Value.X, (float)Value.Y , (float)Value.Z , 0.f }); // LWC_TODO: Precision loss?
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FIntPoint& Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, { uint32(Value.X), uint32(Value.Y), 0u, 0u });
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector2D& Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, { (float)Value.X,(float)Value.Y , 0.f, 0.f }); // LWC_TODO: Precision loss?
|
|
}
|
|
|
|
void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FVector4d& Value)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, FVector4f(Value)); // 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, FRDGTextureUAVRef TextureUAV, const uint32(&ClearValues)[4], FRDGBufferSRVRef RectCoordBufferSRV, uint32 NumRects)
|
|
{
|
|
if (NumRects == 0)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, TextureUAV, ClearValues);
|
|
return;
|
|
}
|
|
|
|
check(TextureUAV && RectCoordBufferSRV);
|
|
|
|
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(GMaxRHIFeatureLevel);
|
|
auto PixelShader = ShaderMap->GetShader<FClearUAVRectsPS>();
|
|
|
|
const FRDGTextureRef Texture = TextureUAV->GetParent();
|
|
const FIntPoint TextureSize = Texture->Desc.Extent;
|
|
|
|
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,
|
|
/*bSkipRenderPass*/ (PassParameters->RenderTargets.GetActiveCount()==0)
|
|
);
|
|
}
|
|
|
|
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)),
|
|
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,
|
|
[](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](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](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, [](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, [](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](FRHICommandList& RHICmdList)
|
|
{
|
|
RHICmdList.ResummarizeHTile(static_cast<FRHITexture2D*>(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](FRHICommandList& RHICmdList)
|
|
{
|
|
Readback->EnqueueCopyRDG(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](FRHICommandList& RHICmdList)
|
|
{
|
|
Readback->EnqueueCopy(RHICmdList, SourceBuffer->GetRHI(), NumBytes);
|
|
});
|
|
}
|
|
|
|
class FClearUAVUIntCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FClearUAVUIntCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FClearUAVUIntCS, FGlobalShader)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, UAV)
|
|
SHADER_PARAMETER(uint32, ClearValue)
|
|
SHADER_PARAMETER(uint32, NumEntries)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return GetMaxSupportedFeatureLevel(Parameters.Platform) >= ERHIFeatureLevel::SM5;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FClearUAVUIntCS, "/Engine/Private/Tools/ClearUAV.usf", "ClearUAVUIntCS", SF_Compute);
|
|
|
|
void FComputeShaderUtils::ClearUAV(FRDGBuilder& GraphBuilder, FGlobalShaderMap* ShaderMap, FRDGBufferUAVRef UAV, uint32 ClearValue)
|
|
{
|
|
FClearUAVUIntCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FClearUAVUIntCS::FParameters>();
|
|
PassParameters->UAV = UAV;
|
|
PassParameters->ClearValue = ClearValue;
|
|
ensure(UAV->Desc.Format == PF_R32_UINT || UAV->Desc.Format == PF_R8_UINT || UAV->Desc.Format == PF_R16_UINT || UAV->Desc.Format == PF_R32_SINT && ClearValue <= MAX_int32);
|
|
PassParameters->NumEntries = UAV->Desc.Buffer->Desc.NumElements;
|
|
check(PassParameters->NumEntries > 0);
|
|
|
|
auto ComputeShader = ShaderMap->GetShader<FClearUAVUIntCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ClearUAV"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(FMath::DivideAndRoundUp<int32>(PassParameters->NumEntries, 64), 1, 1));
|
|
}
|
|
|
|
class FClearUAVFloatCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FClearUAVFloatCS)
|
|
SHADER_USE_PARAMETER_STRUCT(FClearUAVFloatCS, FGlobalShader)
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<float4>, UAVFloat)
|
|
SHADER_PARAMETER(FVector4f, ClearValueFloat)
|
|
SHADER_PARAMETER(uint32, NumEntries)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return GetMaxSupportedFeatureLevel(Parameters.Platform) >= ERHIFeatureLevel::SM5;
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FClearUAVFloatCS, "/Engine/Private/Tools/ClearUAV.usf", "ClearUAVFloatCS", SF_Compute);
|
|
|
|
void FComputeShaderUtils::ClearUAV(FRDGBuilder& GraphBuilder, FGlobalShaderMap* ShaderMap, FRDGBufferUAVRef UAV, FVector4f ClearValue)
|
|
{
|
|
FClearUAVFloatCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FClearUAVFloatCS::FParameters>();
|
|
PassParameters->UAVFloat = UAV;
|
|
PassParameters->ClearValueFloat = ClearValue;
|
|
check(UAV->Desc.Format == PF_A32B32G32R32F || UAV->Desc.Format == PF_FloatRGBA);
|
|
PassParameters->NumEntries = UAV->Desc.Buffer->Desc.NumElements;
|
|
check(PassParameters->NumEntries > 0);
|
|
|
|
auto ComputeShader = ShaderMap->GetShader<FClearUAVFloatCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("ClearUAV"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(FMath::DivideAndRoundUp<int32>(PassParameters->NumEntries, 64), 1, 1));
|
|
}
|
|
|
|
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, FRDGBufferRef& InputCountBuffer, const TCHAR* OutputBufferName, uint32 Divisor, uint32 InputCountOffset, uint32 Multiplier)
|
|
{
|
|
// 1. Add setup pass
|
|
FRDGBufferRef IndirectArgsBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc(4), 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(GMaxRHIFeatureLevel)->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 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, 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;
|
|
}
|
|
|
|
FRDGWaitForTasksScope::~FRDGWaitForTasksScope()
|
|
{
|
|
if (bCondition)
|
|
{
|
|
AddPass(GraphBuilder, RDG_EVENT_NAME("WaitForTasks"), [](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if (IsRunningRHIInSeparateThread())
|
|
{
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_FScopedCommandListWaitForTasks_WaitAsync);
|
|
RHICmdList.ImmediateFlush(EImmediateFlushType::WaitForOutstandingTasksOnly);
|
|
}
|
|
else
|
|
{
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_FScopedCommandListWaitForTasks_Flush);
|
|
CSV_SCOPED_TIMING_STAT(RHITFlushes, FRDGWaitForTasksDtor);
|
|
RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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);
|
|
} |