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

441 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SubsurfaceTiles.h"
#include "SceneRendering.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "Engine/SubsurfaceProfile.h"
bool FSubsurfaceTilePassVS::ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
void FSubsurfaceTilePassVS::ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("SHADER_TILE_VS"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), FSubsurfaceTiles::TileSize);
}
bool FSubsurfaceTileFallbackScreenPassVS::ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
FSubsurfaceTilePassVS::FParameters GetSubsurfaceTileParameters(const FScreenPassTextureViewport& TileViewport, const FSubsurfaceTiles& InTile, FSubsurfaceTiles::ETileType TileType)
{
FSubsurfaceTilePassVS::FParameters Out;
Out.TileType = uint32(TileType);
Out.bRectPrimitive = InTile.bRectPrimitive ? 1 : 0;
Out.ViewMin = TileViewport.Rect.Min;
Out.ViewMax = TileViewport.Rect.Max;
Out.ExtentInverse = FVector2f(1.f / TileViewport.Extent.X, 1.f / TileViewport.Extent.Y);
Out.TileDataBuffer = InTile.GetTileBufferSRV(TileType);
Out.TileIndirectBuffer = InTile.TileIndirectDrawBuffer;
return Out;
}
class FClearUAVBuildIndirectDispatchBufferCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FClearUAVBuildIndirectDispatchBufferCS)
SHADER_USE_PARAMETER_STRUCT(FClearUAVBuildIndirectDispatchBufferCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FIntPoint, ViewportSize)
SHADER_PARAMETER(uint32, Offset)
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint32>, ConditionBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint32>, RWIndirectDispatchArgsBuffer)
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("SUBSURFACE_COMPUTE"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), FSubsurfaceTiles::TileSize);
}
};
IMPLEMENT_GLOBAL_SHADER(FClearUAVBuildIndirectDispatchBufferCS, "/Engine/Private/PostprocessSubsurfaceTile.usf", "BuildIndirectDispatchArgsCS", SF_Compute);
class FClearUAVCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FClearUAVCS)
SHADER_USE_PARAMETER_STRUCT(FClearUAVCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FIntPoint, TextureExtent)
SHADER_PARAMETER(FIntPoint, ViewportMin)
RDG_BUFFER_ACCESS(IndirectDispatchArgsBuffer, ERHIAccess::IndirectArgs)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>,TextureOutput)
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("SUBSURFACE_COMPUTE"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), FSubsurfaceTiles::TileSize);
}
};
IMPLEMENT_GLOBAL_SHADER(FClearUAVCS, "/Engine/Private/PostprocessSubsurfaceTile.usf", "ClearUAV", SF_Compute);
void AddConditionalClearBlackUAVPass(FRDGBuilder& GraphBuilder, FRDGEventName&& Name,
FRDGTextureRef Texture, const FScreenPassTextureViewport& ScreenPassViewport, FRDGBufferRef ConditionBuffer, uint32 Offset)
{
FRDGBufferRef IndirectDispatchArgsBuffer = GraphBuilder.CreateBuffer(
FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(1),
TEXT("IndirectDispatchArgsBuffer"));
{
// build the indirect dispatch arguments buffer ( compute the group count on GPU conditionally)
FClearUAVBuildIndirectDispatchBufferCS::FParameters* PassParameters =
GraphBuilder.AllocParameters<FClearUAVBuildIndirectDispatchBufferCS::FParameters>();
PassParameters->ViewportSize = FIntPoint(ScreenPassViewport.Rect.Max.X - ScreenPassViewport.Rect.Min.X + 1,
ScreenPassViewport.Rect.Max.Y - ScreenPassViewport.Rect.Min.Y + 1);
PassParameters->Offset = Offset;
PassParameters->ConditionBuffer =
GraphBuilder.CreateSRV(ConditionBuffer, EPixelFormat::PF_R32_UINT);
PassParameters->RWIndirectDispatchArgsBuffer =
GraphBuilder.CreateUAV(IndirectDispatchArgsBuffer, EPixelFormat::PF_R32_UINT);
TShaderMapRef<FClearUAVBuildIndirectDispatchBufferCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("SSS::ClearUAV(BuildIndirectDispatchBuffer)"),
ComputeShader,
PassParameters,
FIntVector(1, 1, 1));
}
FClearUAVCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FClearUAVCS::FParameters>();
PassParameters->TextureExtent = Texture->Desc.Extent;
PassParameters->ViewportMin = ScreenPassViewport.Rect.Min;
PassParameters->TextureOutput = GraphBuilder.CreateUAV(Texture);
PassParameters->IndirectDispatchArgsBuffer = IndirectDispatchArgsBuffer;
TShaderMapRef<FClearUAVCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
FComputeShaderUtils::AddPass(
GraphBuilder,
Forward<FRDGEventName>(Name),
ComputeShader,
PassParameters,
IndirectDispatchArgsBuffer, 0);
}
IMPLEMENT_GLOBAL_SHADER(FSubsurfaceTilePassVS, "/Engine/Private/PostProcessSubsurfaceTile.usf", "MainVS", SF_Vertex);
IMPLEMENT_GLOBAL_SHADER(FSubsurfaceTileFallbackScreenPassVS, "/Engine/Private/PostProcessSubsurfaceTile.usf", "SubsurfaceTileFallbackScreenPassVS", SF_Vertex);
const TCHAR* ToString(FSubsurfaceTiles::ETileType Type)
{
switch (Type)
{
case FSubsurfaceTiles::ETileType::All: return TEXT("SSS(All)");
case FSubsurfaceTiles::ETileType::AFIS: return TEXT("SSS(AFIS)");
case FSubsurfaceTiles::ETileType::SEPARABLE: return TEXT("SSS(Separable)");
case FSubsurfaceTiles::ETileType::PASSTHROUGH: return TEXT("SSS(Passthrough)");
case FSubsurfaceTiles::ETileType::AllNonPassthrough: return TEXT("SSS(All,NonPassthrough)");
default: return TEXT("Unknown");
}
}
class FSSSTileCategorisationMarkCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FSSSTileCategorisationMarkCS);
SHADER_USE_PARAMETER_STRUCT(FSSSTileCategorisationMarkCS, FGlobalShader)
class FDimensionHalfRes : SHADER_PERMUTATION_BOOL("SUBSURFACE_HALF_RES");
using FPermutationDomain = TShaderPermutationDomain<FDimensionHalfRes>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER(FVector4f, SubsurfaceParams)
SHADER_PARAMETER(float, SubsurfaceSubpixelThreshold)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Output)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, SubsurfaceInput0)
SHADER_PARAMETER(FIntPoint, TiledViewRes)
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, GroupBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, TileMaskBufferOut)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, TileMaskPassthroughBufferOut)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<uint>, TileMaskNonPassthroughBufferOut)
END_SHADER_PARAMETER_STRUCT()
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
return PermutationVector;
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("TILE_CATERGORISATION_SHADER"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), FSubsurfaceTiles::TileSize);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
}
};
IMPLEMENT_GLOBAL_SHADER(FSSSTileCategorisationMarkCS, "/Engine/Private/PostProcessSubsurfaceTile.usf", "SSSTileCategorisationMarkCS", SF_Compute);
class FSSSTileClassificationBuildListsCS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FSSSTileClassificationBuildListsCS);
SHADER_USE_PARAMETER_STRUCT(FSSSTileClassificationBuildListsCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER(FIntPoint, TiledViewRes)
SHADER_PARAMETER(int, TileType)
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, TileMaskBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWTileTypeCountBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWSSSTileListDataBuffer)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static int32 GetGroupSize()
{
return FSubsurfaceTiles::TileSize;
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("TILE_CATERGORISATION_SHADER"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), GetGroupSize());
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
}
};
IMPLEMENT_GLOBAL_SHADER(FSSSTileClassificationBuildListsCS, "/Engine/Private/PostProcessSubsurfaceTile.usf", "SSSTileClassificationBuildListsCS", SF_Compute);
class FSubsurfaceTileBuildIndirectDispatchArgsCS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FSubsurfaceTileBuildIndirectDispatchArgsCS);
SHADER_USE_PARAMETER_STRUCT(FSubsurfaceTileBuildIndirectDispatchArgsCS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, VertexCountPerInstanceIndirect)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWIndirectDispatchArgsBuffer)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWIndirectDrawArgsBuffer)
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, TileTypeCountBuffer)
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("TILE_CATERGORISATION_SHADER"), 1);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_TILE_SIZE"), FSubsurfaceTiles::TileSize);
OutEnvironment.SetDefine(TEXT("SUBSURFACE_KERNEL_SIZE"), SUBSURFACE_KERNEL_SIZE);
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
IMPLEMENT_GLOBAL_SHADER(FSubsurfaceTileBuildIndirectDispatchArgsCS, "/Engine/Private/PostprocessSubsurfaceTile.usf", "SubsurfaceTileBuildIndirectDispatchArgsCS", SF_Compute);
// Returns the [0, N] clamped value of the 'r.SSS.Scale' CVar.
static float GetSubsurfaceRadiusScaleForTiling()
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.SSS.Scale"));
check(CVar);
return FMath::Max(0.0f, CVar->GetValueOnRenderThread());
}
static float GetSubsurfaceSubpixelThreshold()
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.SSS.Subpixel.Threshold"));
check(CVar);
return FMath::Max(0.0f, CVar->GetValueOnRenderThread());
}
//@TODO: remove the duplicate from PostProcessSubsurface.cpp
FVector4f GetSubsurfaceParams(const FViewInfo& View)
{
const float DistanceToProjectionWindow = View.ViewMatrices.GetProjectionMatrix().M[0][0];
const float SSSScaleZ = DistanceToProjectionWindow * GetSubsurfaceRadiusScaleForTiling();
const float SSSScaleX = SSSScaleZ / SUBSURFACE_KERNEL_SIZE * 0.5f;
return FVector4f(SSSScaleX, SSSScaleZ, 0, 0);
}
/**
* Code adapted from ScreenSpaceReflectionTiles to reduce Setup SSS cost.
* Build lists of 8x8 tiles used by SSS pixels
* Mark and build list steps are separated in order to build a more coherent list (z-ordered over a larger region), which is important for the performance of future passes due to neighbor diffusion.
*/
FSubsurfaceTiles ClassifySSSTiles(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FSceneTextures& SceneTextures,
const FScreenPassTextureViewportParameters SceneViewportParameters, const FScreenPassTextureViewportParameters SubsurfaceViewportParameters, const bool IsHalfRes)
{
FSubsurfaceTiles Result;
{
check(FSubsurfaceTiles::TilePerThread_GroupSize == 64); // If this value change, we need to update the shaders using
check(FSubsurfaceTiles::TileSize == 8); // only size supported for now
FIntPoint SubsurfaceExtent = FIntPoint(SubsurfaceViewportParameters.ViewportSize.X, SubsurfaceViewportParameters.ViewportSize.Y);
Result.TileDimension = FIntPoint::DivideAndRoundUp(SubsurfaceExtent, FSubsurfaceTiles::TileSize);
Result.TileCount = Result.TileDimension.X * Result.TileDimension.Y;
Result.bRectPrimitive = GRHISupportsRectTopology;
Result.TileTypeCountBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), FSubsurfaceTiles::TileTypeCount), TEXT("Subsurface.TileCountBuffer"));
Result.TileTypeCountSRV = GraphBuilder.CreateSRV(Result.TileTypeCountBuffer,EPixelFormat::PF_R32_UINT);
Result.TileIndirectDispatchBuffer =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDispatchIndirectParameters>(FSubsurfaceTiles::TileTypeCount), TEXT("Subsurface.TileIndirectDispatchBuffer"));
Result.TileIndirectDrawBuffer =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc<FRHIDrawIndirectParameters>(FSubsurfaceTiles::TileTypeCount), TEXT("Subsurface.TileIndirectDrawBuffer"));
Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::All)] =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileCount), TEXT("Subsurface.TileDataBuffer(All)"));
Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::AFIS)] =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileCount), TEXT("Subsurface.TileDataBuffer(AFIS)"));
Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::SEPARABLE)] =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileCount), TEXT("Subsurface.TileDataBuffer(SEPARABLE)"));
Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::PASSTHROUGH)] =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileCount), TEXT("Subsurface.TileDataBuffer(PASSTHROUGH)"));
Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::AllNonPassthrough)] =
GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileCount), TEXT("Subsurface.TileDataBuffer(AllNonPassthrough)"));
for (uint32 BufferIt = 0; BufferIt < FSubsurfaceTiles::TileTypeCount; ++BufferIt)
{
if (Result.TileDataBuffer[BufferIt])
{
Result.TileDataSRV[BufferIt] = GraphBuilder.CreateSRV(Result.TileDataBuffer[BufferIt], PF_R32_UINT);
}
}
// We write to FSubsurfaceTiles::All, FSubsurfaceTiles::AllNonPassthrough, and FSubsurfaceTiles::Passthrough
FRDGBufferRef TileListDataBuffer = Result.TileDataBuffer[ToIndex(FSubsurfaceTiles::ETileType::All)];//GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), Result.TileDimension.X * Result.TileDimension.Y), TEXT("Subsurface.TileListDataBuffer"));
FRDGBufferSRVRef TileListDataBufferSRV = Result.TileDataSRV[ToIndex(FSubsurfaceTiles::ETileType::All)];//GraphBuilder.CreateSRV(TileListDataBuffer, PF_R32_UINT);
FRDGBufferUAVRef DrawIndirectParametersBufferUAV = GraphBuilder.CreateUAV(Result.TileIndirectDrawBuffer, EPixelFormat::PF_R32_UINT);
FRDGBufferUAVRef DispatchIndirectParametersBufferUAV = GraphBuilder.CreateUAV(Result.TileIndirectDispatchBuffer, EPixelFormat::PF_R32_UINT);
// Allocate buffer with 1 bit / tile
FRDGBufferRef TileMaskBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), FMath::DivideAndRoundUp(Result.TileDimension.X * Result.TileDimension.Y, 32)), TEXT("SSR.Classify.TileMaskBuffer"));
FRDGBufferUAVRef TileMaskBufferUAV = GraphBuilder.CreateUAV(TileMaskBuffer);
FRDGBufferRef TileMaskPassthroughBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), FMath::DivideAndRoundUp(Result.TileDimension.X * Result.TileDimension.Y, 32)), TEXT("SSR.Classify.TileMaskPassthroughBuffer"));
FRDGBufferUAVRef TileMaskPassthroughBufferUAV = GraphBuilder.CreateUAV(TileMaskPassthroughBuffer);
FRDGBufferRef TileMaskNonPassthroughBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateStructuredDesc(sizeof(uint32), FMath::DivideAndRoundUp(Result.TileDimension.X * Result.TileDimension.Y, 32)), TEXT("SSR.Classify.TileMaskNonPassthroughBuffer"));
FRDGBufferUAVRef TileMaskNonPassthroughBufferUAV = GraphBuilder.CreateUAV(TileMaskNonPassthroughBuffer);
AddClearUAVPass(GraphBuilder, TileMaskBufferUAV, 0);
AddClearUAVPass(GraphBuilder, TileMaskPassthroughBufferUAV, 0);
AddClearUAVPass(GraphBuilder, TileMaskNonPassthroughBufferUAV, 0);
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(Result.TileTypeCountBuffer,EPixelFormat::PF_R32_UINT), 0);
// Mark used tiles based on SHADING_MODEL_ID, and whether it is subpixel scattering only.
{
typedef FSSSTileCategorisationMarkCS SHADER;
SHADER::FPermutationDomain PermutationVector;
PermutationVector.Set<SHADER::FDimensionHalfRes>(IsHalfRes);
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap, PermutationVector);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->SceneTextures = SceneTextures.UniformBuffer;
PassParameters->View = View.GetShaderParameters();
PassParameters->SubsurfaceParams = GetSubsurfaceParams(View);
PassParameters->SubsurfaceSubpixelThreshold = GetSubsurfaceSubpixelThreshold();
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
PassParameters->Output = SubsurfaceViewportParameters;
PassParameters->SubsurfaceInput0 = SceneViewportParameters;
PassParameters->TiledViewRes = Result.TileDimension;
PassParameters->TileMaskBufferOut = TileMaskBufferUAV;
PassParameters->TileMaskPassthroughBufferOut = TileMaskPassthroughBufferUAV;
PassParameters->TileMaskNonPassthroughBufferOut = TileMaskNonPassthroughBufferUAV;
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("SSS::TileCategorisationMarkTiles(All)"),
ComputeShader,
PassParameters,
FIntVector(Result.TileDimension.X, Result.TileDimension.Y, 1)
);
}
// Build compacted and coherent z-order tile lists from bit-marked tiles
{
typedef FSSSTileClassificationBuildListsCS SHADER;
struct FSubsurfaceBuildListsInfo
{
FSubsurfaceBuildListsInfo( FSubsurfaceTiles::ETileType inTileType, FRDGBufferRef inInput, FRDGBufferRef inOutput)
: Name(ToString(inTileType)), TileType(inTileType), Input(inInput), Output(inOutput)
{}
const TCHAR* Name;
FSubsurfaceTiles::ETileType TileType;
FRDGBufferRef Input;
FRDGBufferRef Output;
};
const int NumOfBuildListsPass = 3;
const FSubsurfaceBuildListsInfo SubsurfaceBuildListsInfo[NumOfBuildListsPass] =
{
{FSubsurfaceTiles::ETileType::All, TileMaskBuffer, Result.GetTileBuffer(FSubsurfaceTiles::ETileType::All)},
{FSubsurfaceTiles::ETileType::PASSTHROUGH, TileMaskPassthroughBuffer, Result.GetTileBuffer(FSubsurfaceTiles::ETileType::PASSTHROUGH)},
{FSubsurfaceTiles::ETileType::AllNonPassthrough, TileMaskNonPassthroughBuffer, Result.GetTileBuffer(FSubsurfaceTiles::ETileType::AllNonPassthrough)}
};
for (int PassIndex = 0 ; PassIndex < NumOfBuildListsPass ; ++PassIndex)
{
const FSubsurfaceBuildListsInfo PassInfo = SubsurfaceBuildListsInfo[PassIndex];
TShaderMapRef<SHADER> ComputeShader(View.ShaderMap);
SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<SHADER::FParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->TiledViewRes = Result.TileDimension;
PassParameters->TileType = ToIndex(PassInfo.TileType);
PassParameters->TileMaskBuffer = GraphBuilder.CreateSRV(PassInfo.Input);
PassParameters->RWTileTypeCountBuffer = GraphBuilder.CreateUAV(Result.TileTypeCountBuffer, PF_R32_UINT);
PassParameters->RWSSSTileListDataBuffer = GraphBuilder.CreateUAV(PassInfo.Output, PF_R32_UINT);
FComputeShaderUtils::AddPass(
GraphBuilder,
RDG_EVENT_NAME("SSS::TileCategorisationBuildList(%s)",
PassInfo.Name),
ComputeShader,
PassParameters,
FComputeShaderUtils::GetGroupCount(Result.TileDimension, SHADER::GetGroupSize())
);
}
// Setup the indirect dispatch & draw arguments for All, PASSTHROUGH, and AllNonPassthrough.
{
typedef FSubsurfaceTileBuildIndirectDispatchArgsCS ARGSETUPSHADER;
ARGSETUPSHADER::FParameters* PassParameters = GraphBuilder.AllocParameters<ARGSETUPSHADER::FParameters>();
PassParameters->VertexCountPerInstanceIndirect = GRHISupportsRectTopology ? 4 : 6;
PassParameters->RWIndirectDispatchArgsBuffer = DispatchIndirectParametersBufferUAV;
PassParameters->RWIndirectDrawArgsBuffer = DrawIndirectParametersBufferUAV;
PassParameters->TileTypeCountBuffer = Result.TileTypeCountSRV;
TShaderMapRef<ARGSETUPSHADER> ComputeShader(View.ShaderMap);
FComputeShaderUtils::AddPass(GraphBuilder, FRDGEventName(TEXT("SSS::BuildIndirectArgs(Dispatch & Draw)")), ComputeShader, PassParameters, FIntVector(1, 1, 1));
}
}
}
return Result;
}