// 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, ConditionBuffer) SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, 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,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(1), TEXT("IndirectDispatchArgsBuffer")); { // build the indirect dispatch arguments buffer ( compute the group count on GPU conditionally) FClearUAVBuildIndirectDispatchBufferCS::FParameters* PassParameters = GraphBuilder.AllocParameters(); 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 ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderUtils::AddPass( GraphBuilder, RDG_EVENT_NAME("SSS::ClearUAV(BuildIndirectDispatchBuffer)"), ComputeShader, PassParameters, FIntVector(1, 1, 1)); } FClearUAVCS::FParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->TextureExtent = Texture->Desc.Extent; PassParameters->ViewportMin = ScreenPassViewport.Rect.Min; PassParameters->TextureOutput = GraphBuilder.CreateUAV(Texture); PassParameters->IndirectDispatchArgsBuffer = IndirectDispatchArgsBuffer; TShaderMapRef ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderUtils::AddPass( GraphBuilder, Forward(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; 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, GroupBuffer) SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, TileMaskBufferOut) SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, TileMaskPassthroughBufferOut) SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, 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, TileMaskBuffer) SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, RWTileTypeCountBuffer) SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, 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, RWIndirectDispatchArgsBuffer) SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, RWIndirectDrawArgsBuffer) SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer, 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(FSubsurfaceTiles::TileTypeCount), TEXT("Subsurface.TileIndirectDispatchBuffer")); Result.TileIndirectDrawBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateIndirectDesc(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(IsHalfRes); TShaderMapRef ComputeShader(View.ShaderMap, PermutationVector); SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters(); 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 ComputeShader(View.ShaderMap); SHADER::FParameters* PassParameters = GraphBuilder.AllocParameters(); 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(); PassParameters->VertexCountPerInstanceIndirect = GRHISupportsRectTopology ? 4 : 6; PassParameters->RWIndirectDispatchArgsBuffer = DispatchIndirectParametersBufferUAV; PassParameters->RWIndirectDrawArgsBuffer = DrawIndirectParametersBufferUAV; PassParameters->TileTypeCountBuffer = Result.TileTypeCountSRV; TShaderMapRef ComputeShader(View.ShaderMap); FComputeShaderUtils::AddPass(GraphBuilder, FRDGEventName(TEXT("SSS::BuildIndirectArgs(Dispatch & Draw)")), ComputeShader, PassParameters, FIntVector(1, 1, 1)); } } } return Result; }