You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
331 lines
14 KiB
C++
331 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "RenderGraphResources.h"
|
|
#include "RenderGraphBuilder.h"
|
|
#include "Shader.h"
|
|
#include "ShaderParameterStruct.h"
|
|
#include "ShaderParameterMacros.h"
|
|
|
|
class FGlobalShaderMap;
|
|
|
|
/** An empty shader parameter structure ready to be used anywhere. */
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FEmptyShaderParameters, RENDERCORE_API)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
/** Useful parameter struct that only have render targets.
|
|
*
|
|
* FRenderTargetParameters PassParameters;
|
|
* PassParameters.RenderTargets.DepthStencil = ... ;
|
|
* PassParameters.RenderTargets[0] = ... ;
|
|
*/
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FRenderTargetParameters, RENDERCORE_API)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
/**
|
|
* Clears all render graph tracked resources that are not bound by a shader.
|
|
* Excludes any resources on the ExcludeList from being cleared regardless of whether the
|
|
* shader binds them or not. This is needed for resources that are used outside of shader
|
|
* bindings such as indirect arguments buffers.
|
|
*/
|
|
extern RENDERCORE_API void ClearUnusedGraphResourcesImpl(
|
|
const FShaderParameterBindings& ShaderBindings,
|
|
const FShaderParametersMetadata* ParametersMetadata,
|
|
void* InoutParameters,
|
|
std::initializer_list<FRDGResourceRef> ExcludeList);
|
|
|
|
/** Similar to the function above, but takes a list of shader bindings and only clears if none of the shaders contain the resource. */
|
|
extern RENDERCORE_API void ClearUnusedGraphResourcesImpl(
|
|
TArrayView<const FShaderParameterBindings*> ShaderBindingsList,
|
|
const FShaderParametersMetadata* ParametersMetadata,
|
|
void* InoutParameters,
|
|
std::initializer_list<FRDGResourceRef> ExcludeList);
|
|
|
|
template <typename TShaderClass>
|
|
void ClearUnusedGraphResources(
|
|
const TShaderRef<TShaderClass>& Shader,
|
|
typename TShaderClass::FParameters* InoutParameters,
|
|
std::initializer_list<FRDGResourceRef> ExcludeList = {})
|
|
{
|
|
const FShaderParametersMetadata* ParametersMetadata = TShaderClass::FParameters::FTypeInfo::GetStructMetadata();
|
|
|
|
// Verify the shader have all the parameters it needs. This is done before the
|
|
// ClearUnusedGraphResourcesImpl() to not mislead user on why some resource are missing
|
|
// when debugging a validation failure.
|
|
ValidateShaderParameters(Shader, ParametersMetadata, InoutParameters);
|
|
|
|
// Clear the resources the shader won't need.
|
|
return ClearUnusedGraphResourcesImpl(Shader->Bindings, ParametersMetadata, InoutParameters, ExcludeList);
|
|
}
|
|
|
|
template <typename TShaderClassA, typename TShaderClassB, typename TPassParameterStruct>
|
|
void ClearUnusedGraphResources(
|
|
const TShaderRef<TShaderClassA>& ShaderA,
|
|
const TShaderRef<TShaderClassB>& ShaderB,
|
|
TPassParameterStruct* InoutParameters,
|
|
std::initializer_list<FRDGResourceRef> ExcludeList = {})
|
|
{
|
|
static_assert(TIsSame<typename TShaderClassA::FParameters, TPassParameterStruct>::Value, "First shader FParameter type must match pass parameters.");
|
|
static_assert(TIsSame<typename TShaderClassB::FParameters, TPassParameterStruct>::Value, "Second shader FParameter type must match pass parameters.");
|
|
const FShaderParametersMetadata* ParametersMetadata = TPassParameterStruct::FTypeInfo::GetStructMetadata();
|
|
|
|
// Verify the shader have all the parameters it needs. This is done before the
|
|
// ClearUnusedGraphResourcesImpl() to not mislead user on why some resource are missing
|
|
// when debugging a validation failure.
|
|
ValidateShaderParameters(ShaderA, ParametersMetadata, InoutParameters);
|
|
ValidateShaderParameters(ShaderB, ParametersMetadata, InoutParameters);
|
|
|
|
// Clear the resources the shader won't need.
|
|
const FShaderParameterBindings* ShaderBindings[] = { &ShaderA->Bindings, &ShaderB->Bindings };
|
|
return ClearUnusedGraphResourcesImpl(ShaderBindings, ParametersMetadata, InoutParameters, ExcludeList);
|
|
}
|
|
|
|
/**
|
|
* Register external texture with fallback if the resource is invalid.
|
|
*
|
|
* CAUTION: use this function very wisely. It may actually remove shader parameter validation
|
|
* failure when a pass is actually trying to access a resource not yet or no longer available.
|
|
*/
|
|
RENDERCORE_API FRDGTextureRef RegisterExternalTextureWithFallback(
|
|
FRDGBuilder& GraphBuilder,
|
|
const TRefCountPtr<IPooledRenderTarget>& ExternalPooledTexture,
|
|
const TRefCountPtr<IPooledRenderTarget>& FallbackPooledTexture,
|
|
const TCHAR* ExternalPooledTextureName = TEXT("External"));
|
|
|
|
/** All utils for compute shaders.
|
|
*/
|
|
struct RENDERCORE_API FComputeShaderUtils
|
|
{
|
|
/** Ideal size of group size 8x8 to occupy at least an entire wave on GCN, two warp on Nvidia. */
|
|
static constexpr int32 kGolden2DGroupSize = 8;
|
|
|
|
/** Compute the number of group to dispatch. */
|
|
static FIntVector GetGroupCount(const int32 ThreadCount, const int32 GroupSize)
|
|
{
|
|
return FIntVector(
|
|
FMath::DivideAndRoundUp(ThreadCount, GroupSize),
|
|
1,
|
|
1);
|
|
}
|
|
static FIntVector GetGroupCount(const FIntPoint& ThreadCount, const FIntPoint& GroupSize)
|
|
{
|
|
return FIntVector(
|
|
FMath::DivideAndRoundUp(ThreadCount.X, GroupSize.X),
|
|
FMath::DivideAndRoundUp(ThreadCount.Y, GroupSize.Y),
|
|
1);
|
|
}
|
|
static FIntVector GetGroupCount(const FIntPoint& ThreadCount, const int32 GroupSize)
|
|
{
|
|
return FIntVector(
|
|
FMath::DivideAndRoundUp(ThreadCount.X, GroupSize),
|
|
FMath::DivideAndRoundUp(ThreadCount.Y, GroupSize),
|
|
1);
|
|
}
|
|
static FIntVector GetGroupCount(const FIntVector& ThreadCount, const FIntVector& GroupSize)
|
|
{
|
|
return FIntVector(
|
|
FMath::DivideAndRoundUp(ThreadCount.X, GroupSize.X),
|
|
FMath::DivideAndRoundUp(ThreadCount.Y, GroupSize.Y),
|
|
FMath::DivideAndRoundUp(ThreadCount.Z, GroupSize.Z));
|
|
}
|
|
|
|
|
|
/** Dispatch a compute shader to rhi command list with its parameters. */
|
|
template<typename TShaderClass>
|
|
static void Dispatch(FRHICommandList& RHICmdList, const TShaderRef<TShaderClass>& ComputeShader, const typename TShaderClass::FParameters& Parameters, FIntVector GroupCount)
|
|
{
|
|
FRHIComputeShader* ShaderRHI = ComputeShader.GetComputeShader();
|
|
RHICmdList.SetComputeShader(ShaderRHI);
|
|
SetShaderParameters(RHICmdList, ComputeShader, ShaderRHI, Parameters);
|
|
RHICmdList.DispatchComputeShader(GroupCount.X, GroupCount.Y, GroupCount.Z);
|
|
UnsetShaderUAVs(RHICmdList, ComputeShader, ShaderRHI);
|
|
}
|
|
|
|
/** Indirect dispatch a compute shader to rhi command list with its parameters. */
|
|
template<typename TShaderClass>
|
|
static void DispatchIndirect(
|
|
FRHICommandList& RHICmdList,
|
|
const TShaderRef<TShaderClass>& ComputeShader,
|
|
const typename TShaderClass::FParameters& Parameters,
|
|
FRHIVertexBuffer* IndirectArgsBuffer,
|
|
uint32 IndirectArgOffset)
|
|
{
|
|
FRHIComputeShader* ShaderRHI = ComputeShader.GetComputeShader();
|
|
RHICmdList.SetComputeShader(ShaderRHI);
|
|
SetShaderParameters(RHICmdList, ComputeShader, ShaderRHI, Parameters);
|
|
RHICmdList.DispatchIndirectComputeShader(IndirectArgsBuffer, IndirectArgOffset);
|
|
UnsetShaderUAVs(RHICmdList, ComputeShader, ShaderRHI);
|
|
}
|
|
|
|
/** Dispatch a compute shader to rhi command list with its parameters and indirect args. */
|
|
template<typename TShaderClass>
|
|
static FORCEINLINE_DEBUGGABLE void DispatchIndirect(
|
|
FRHICommandList& RHICmdList,
|
|
const TShaderClass* ComputeShader,
|
|
const typename TShaderClass::FParameters& Parameters,
|
|
FRDGBufferRef IndirectArgsBuffer,
|
|
uint32 IndirectArgOffset)
|
|
{
|
|
FRHIComputeShader* ShaderRHI = ComputeShader->GetComputeShader();
|
|
RHICmdList.SetComputeShader(ShaderRHI);
|
|
SetShaderParameters(RHICmdList, ComputeShader, ShaderRHI, Parameters);
|
|
RHICmdList.DispatchIndirectComputeShader(IndirectArgsBuffer->GetIndirectRHICallBuffer(), IndirectArgOffset);
|
|
UnsetShaderUAVs(RHICmdList, ComputeShader, ShaderRHI);
|
|
}
|
|
|
|
/** Dispatch a compute shader to render graph builder with its parameters. */
|
|
template<typename TShaderClass>
|
|
static void AddPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGEventName&& PassName,
|
|
const TShaderRef<TShaderClass>& ComputeShader,
|
|
typename TShaderClass::FParameters* Parameters,
|
|
FIntVector GroupCount)
|
|
{
|
|
ClearUnusedGraphResources(ComputeShader, Parameters);
|
|
|
|
GraphBuilder.AddPass(
|
|
Forward<FRDGEventName>(PassName),
|
|
Parameters,
|
|
ERDGPassFlags::Compute,
|
|
[Parameters, ComputeShader, GroupCount](FRHICommandList& RHICmdList)
|
|
{
|
|
FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *Parameters, GroupCount);
|
|
});
|
|
}
|
|
|
|
/** Dispatch a compute shader to render graph builder with its parameters. */
|
|
template<typename TShaderClass>
|
|
static void AddPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGEventName&& PassName,
|
|
const TShaderRef<TShaderClass>& ComputeShader,
|
|
typename TShaderClass::FParameters* Parameters,
|
|
FRDGBufferRef IndirectArgsBuffer,
|
|
uint32 IndirectArgOffset)
|
|
{
|
|
checkf(IndirectArgsBuffer->Desc.Usage & BUF_DrawIndirect, TEXT("The buffer %s was not flagged for indirect draw parameters"), IndirectArgsBuffer->Name);
|
|
|
|
ClearUnusedGraphResources(ComputeShader, Parameters, { IndirectArgsBuffer });
|
|
|
|
GraphBuilder.AddPass(
|
|
Forward<FRDGEventName>(PassName),
|
|
Parameters,
|
|
ERDGPassFlags::Compute,
|
|
[Parameters, ComputeShader, IndirectArgsBuffer, IndirectArgOffset](FRHICommandList& RHICmdList)
|
|
{
|
|
// Marks the indirect draw parameter as used by the pass manually, given it can't be bound directly by any of the shader,
|
|
// meaning SetShaderParameters() won't be able to do it.
|
|
IndirectArgsBuffer->MarkResourceAsUsed();
|
|
|
|
FComputeShaderUtils::DispatchIndirect(RHICmdList, ComputeShader, *Parameters, IndirectArgsBuffer->GetIndirectRHICallBuffer(), IndirectArgOffset);
|
|
});
|
|
}
|
|
|
|
static void ClearUAV(FRDGBuilder& GraphBuilder, FGlobalShaderMap* ShaderMap, FRDGBufferUAVRef UAV, uint32 ClearValue);
|
|
static void ClearUAV(FRDGBuilder& GraphBuilder, FGlobalShaderMap* ShaderMap, FRDGBufferUAVRef UAV, FVector4 ClearValue);
|
|
};
|
|
/** Adds a render graph pass to copy a region from one texture to another. Uses RHICopyTexture under the hood.
|
|
* Formats of the two textures must match. The output and output texture regions be within the respective extents.
|
|
*/
|
|
RENDERCORE_API void AddCopyTexturePass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef OutputTexture,
|
|
const FRHICopyTextureInfo& CopyInfo);
|
|
|
|
/** Simpler variant of the above function for 2D textures.
|
|
* @param InputPosition The pixel position within the input texture of the top-left corner of the box.
|
|
* @param OutputPosition The pixel position within the output texture of the top-left corner of the box.
|
|
* @param Size The size in pixels of the region to copy from input to output. If zero, the full extent of
|
|
* the input texture is copied.
|
|
*/
|
|
inline void AddCopyTexturePass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef OutputTexture,
|
|
FIntPoint InputPosition = FIntPoint::ZeroValue,
|
|
FIntPoint OutputPosition = FIntPoint::ZeroValue,
|
|
FIntPoint Size = FIntPoint::ZeroValue)
|
|
{
|
|
FRHICopyTextureInfo CopyInfo;
|
|
CopyInfo.SourcePosition.X = InputPosition.X;
|
|
CopyInfo.SourcePosition.Y = InputPosition.Y;
|
|
CopyInfo.DestPosition.X = OutputPosition.X;
|
|
CopyInfo.DestPosition.Y = OutputPosition.Y;
|
|
if (Size != FIntPoint::ZeroValue)
|
|
{
|
|
CopyInfo.Size = FIntVector(Size.X, Size.Y, 1);
|
|
}
|
|
AddCopyTexturePass(GraphBuilder, InputTexture, OutputTexture, CopyInfo);
|
|
}
|
|
|
|
/** Adds a render graph pass to resolve from one texture to another. Uses RHICopyToResolveTarget under the hood.
|
|
* The formats of the two textures don't need to match.
|
|
*/
|
|
RENDERCORE_API void AddCopyToResolveTargetPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGTextureRef InputTexture,
|
|
FRDGTextureRef OutputTexture,
|
|
const FResolveParams& ResolveParams);
|
|
|
|
/** Adds a render graph pass to clear a texture or buffer UAV with a single typed value. */
|
|
RENDERCORE_API void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGBufferUAVRef BufferUAV, uint32 Value);
|
|
|
|
RENDERCORE_API void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const float(&ClearValues)[4]);
|
|
|
|
RENDERCORE_API void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const uint32(&ClearValues)[4]);
|
|
|
|
RENDERCORE_API void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const FLinearColor& ClearColor);
|
|
|
|
/** Clears parts of UAV specified by an array of screen rects. If no rects are specific, then it falls back to a standard UAV clear. */
|
|
RENDERCORE_API void AddClearUAVPass(FRDGBuilder& GraphBuilder, FRDGTextureUAVRef TextureUAV, const uint32(&ClearValues)[4], FRDGBufferSRVRef RectMinMaxBufferSRV, uint32 NumRects);
|
|
|
|
/** Adds a render graph pass to clear a render target. Prefer to use clear actions if possible. */
|
|
RENDERCORE_API void AddClearRenderTargetPass(FRDGBuilder& GraphBuilder, FRDGTextureRef Texture, const FLinearColor& ClearColor);
|
|
|
|
/** Adds a render graph pass to clear a depth stencil target. Prefer to use clear actions if possible. */
|
|
RENDERCORE_API void AddClearDepthStencilPass(
|
|
FRDGBuilder& GraphBuilder,
|
|
FRDGTextureRef Texture,
|
|
bool bClearDepth,
|
|
float Depth,
|
|
bool bClearStencil,
|
|
uint8 Stencil);
|
|
|
|
enum class ERDGInitialDataFlags : uint8
|
|
{
|
|
/** Specifies the default behavior, which is to make a copy of the initial data for replay when
|
|
* the graph is executed. The user does not need to preserve lifetime of the data pointer.
|
|
*/
|
|
None = 0,
|
|
|
|
/** Specifies that the user will maintain ownership of the data until the graph is executed. The
|
|
* upload pass will only use a reference to store the data. Use caution with this flag since graph
|
|
* execution is deferred! Useful to avoid the copy if the initial data lifetime is guaranteed to
|
|
* outlive the graph.
|
|
*/
|
|
NoCopy = 0x1
|
|
};
|
|
ENUM_CLASS_FLAGS(ERDGInitialDataFlags)
|
|
|
|
/** Creates a structured buffer with initial data by creating an upload pass. */
|
|
RENDERCORE_API FRDGBufferRef CreateStructuredBuffer(
|
|
FRDGBuilder& GraphBuilder,
|
|
const TCHAR* Name,
|
|
uint32 BytesPerElement,
|
|
uint32 NumElements,
|
|
const void* InitialData,
|
|
uint64 InitialDataSize,
|
|
ERDGInitialDataFlags InitialDataFlags = ERDGInitialDataFlags::None);
|
|
|
|
/** Creates a vertex buffer with initial data by creating an upload pass. */
|
|
RENDERCORE_API FRDGBufferRef CreateVertexBuffer(
|
|
FRDGBuilder& GraphBuilder,
|
|
const TCHAR* Name,
|
|
const FRDGBufferDesc& Desc,
|
|
const void* InitialData,
|
|
uint64 InitialDataSize,
|
|
ERDGInitialDataFlags InitialDataFlags = ERDGInitialDataFlags::None); |