You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Don't compile distance field shader permutations if bUseDistanceFields is unset or false Added UAV output to pixel shader Clear Tiny UAV uses command buffer ClearBuffer command instead of allocating a temp buffer and copying it to UAV anthony.bills #rnx #ROBOMERGE-OWNER: ryan.vance #ROBOMERGE-AUTHOR: mickael.gilabert #ROBOMERGE-SOURCE: CL 6077502 via CL 6077551 via CL 6080478 via CL 6080627 #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 6084211 by mickael gilabert in Dev-VR branch]
706 lines
31 KiB
C++
706 lines
31 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DistanceFieldObjectCulling.cpp
|
|
=============================================================================*/
|
|
|
|
#include "DistanceFieldAmbientOcclusion.h"
|
|
#include "DeferredShadingRenderer.h"
|
|
#include "PostProcess/PostProcessing.h"
|
|
#include "PostProcess/SceneFilterRendering.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
#include "ScreenRendering.h"
|
|
#include "DistanceFieldLightingPost.h"
|
|
#include "OneColorShader.h"
|
|
#include "GlobalDistanceField.h"
|
|
#include "FXSystem.h"
|
|
#include "PostProcess/PostProcessSubsurface.h"
|
|
#include "PipelineStateCache.h"
|
|
#include "ClearQuad.h"
|
|
|
|
int32 GAOScatterTileCulling = 1;
|
|
FAutoConsoleVariableRef CVarAOScatterTileCulling(
|
|
TEXT("r.AOScatterTileCulling"),
|
|
GAOScatterTileCulling,
|
|
TEXT("Whether to use the rasterizer for binning occluder objects into screenspace tiles."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GAverageDistanceFieldObjectsPerCullTile = 512;
|
|
FAutoConsoleVariableRef CVarMaxDistanceFieldObjectsPerCullTile(
|
|
TEXT("r.AOAverageObjectsPerCullTile"),
|
|
GAverageDistanceFieldObjectsPerCullTile,
|
|
TEXT("Determines how much memory should be allocated in distance field object culling data structures. Too much = memory waste, too little = flickering due to buffer overflow."),
|
|
ECVF_RenderThreadSafe | ECVF_ReadOnly
|
|
);
|
|
|
|
class FCircleVertexBuffer : public FVertexBuffer
|
|
{
|
|
public:
|
|
|
|
int32 NumSections;
|
|
|
|
FCircleVertexBuffer()
|
|
{
|
|
NumSections = 8;
|
|
}
|
|
|
|
virtual void InitRHI() override
|
|
{
|
|
// Used as a non-indexed triangle list, so 3 vertices per triangle
|
|
const uint32 Size = 3 * NumSections * sizeof(FScreenVertex);
|
|
FRHIResourceCreateInfo CreateInfo;
|
|
void* Buffer = nullptr;
|
|
VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Static, CreateInfo, Buffer);
|
|
FScreenVertex* DestVertex = (FScreenVertex*)Buffer;
|
|
|
|
const float RadiansPerRingSegment = PI / (float)NumSections;
|
|
|
|
// Boost the effective radius so that the edges of the circle approximation lie on the circle, instead of the vertices
|
|
const float Radius = 1.0f / FMath::Cos(RadiansPerRingSegment);
|
|
|
|
for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++)
|
|
{
|
|
float Fraction = SectionIndex / (float)NumSections;
|
|
float CurrentAngle = Fraction * 2 * PI;
|
|
float NextAngle = ((SectionIndex + 1) / (float)NumSections) * 2 * PI;
|
|
FVector2D CurrentPosition(Radius * FMath::Cos(CurrentAngle), Radius * FMath::Sin(CurrentAngle));
|
|
FVector2D NextPosition(Radius * FMath::Cos(NextAngle), Radius * FMath::Sin(NextAngle));
|
|
|
|
DestVertex[SectionIndex * 3 + 0].Position = FVector2D(0, 0);
|
|
DestVertex[SectionIndex * 3 + 0].UV = CurrentPosition;
|
|
DestVertex[SectionIndex * 3 + 1].Position = FVector2D(0, 0);
|
|
DestVertex[SectionIndex * 3 + 1].UV = NextPosition;
|
|
DestVertex[SectionIndex * 3 + 2].Position = FVector2D(0, 0);
|
|
DestVertex[SectionIndex * 3 + 2].UV = FVector2D(.5f, .5f);
|
|
}
|
|
|
|
RHIUnlockVertexBuffer(VertexBufferRHI);
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FCircleVertexBuffer> GCircleVertexBuffer;
|
|
TGlobalResource<FDistanceFieldObjectBufferResource> GAOCulledObjectBuffers;
|
|
|
|
void FTileIntersectionResources::InitDynamicRHI()
|
|
{
|
|
const uint32 FastVRamFlag = GFastVRamConfig.DistanceFieldTileIntersectionResources | (IsTransientResourceBufferAliasingEnabled() ? BUF_Transient : BUF_None);
|
|
TileConeAxisAndCos.Initialize(sizeof(FVector4), TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static | FastVRamFlag, TEXT("TileConeAxisAndCos"));
|
|
TileConeDepthRanges.Initialize(sizeof(FVector4), TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static | FastVRamFlag, TEXT("TileConeDepthRanges"));
|
|
|
|
NumCulledTilesArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static | FastVRamFlag, TEXT("NumCulledTilesArray"));
|
|
CulledTilesStartOffsetArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static | FastVRamFlag, TEXT("CulledTilesStartOffsetArray"));
|
|
|
|
// Can only use 16 bit for CulledTileDataArray if few enough objects and tiles
|
|
const bool b16BitObjectIndices = MaxSceneObjects < (1 << 16);
|
|
const bool b16BitCulledTileIndexBuffer = bAllow16BitIndices && b16BitObjectIndices && TileDimensions.X * TileDimensions.Y < (1 << 16);
|
|
CulledTileDataArray.Initialize(
|
|
b16BitCulledTileIndexBuffer ? sizeof(uint16) : sizeof(uint32),
|
|
GAverageDistanceFieldObjectsPerCullTile * TileDimensions.X * TileDimensions.Y * CulledTileDataStride,
|
|
b16BitCulledTileIndexBuffer ? PF_R16_UINT : PF_R32_UINT,
|
|
BUF_Static | FastVRamFlag,
|
|
TEXT("CulledTileDataArray"));
|
|
ObjectTilesIndirectArguments.Initialize(sizeof(uint32), 3, PF_R32_UINT, BUF_Static | BUF_DrawIndirect);
|
|
}
|
|
|
|
class FCullObjectsForViewCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCullObjectsForViewCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
}
|
|
|
|
FCullObjectsForViewCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
ObjectBufferParameters.Bind(Initializer.ParameterMap);
|
|
CulledObjectParameters.Bind(Initializer.ParameterMap);
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
NumConvexHullPlanes.Bind(Initializer.ParameterMap, TEXT("NumConvexHullPlanes"));
|
|
ViewFrustumConvexHull.Bind(Initializer.ParameterMap, TEXT("ViewFrustumConvexHull"));
|
|
ObjectBoundingGeometryIndexCount.Bind(Initializer.ParameterMap, TEXT("ObjectBoundingGeometryIndexCount"));
|
|
}
|
|
|
|
FCullObjectsForViewCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FScene* Scene, const FSceneView& View, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[6];
|
|
OutUAVs[0] = GAOCulledObjectBuffers.Buffers.ObjectIndirectArguments.UAV;
|
|
OutUAVs[1] = GAOCulledObjectBuffers.Buffers.Bounds.UAV;
|
|
OutUAVs[2] = GAOCulledObjectBuffers.Buffers.Data.UAV;
|
|
OutUAVs[3] = GAOCulledObjectBuffers.Buffers.BoxBounds.UAV;
|
|
OutUAVs[4] = Scene->DistanceFieldSceneData.ObjectBuffers->Data.UAV;
|
|
OutUAVs[5] = Scene->DistanceFieldSceneData.ObjectBuffers->Bounds.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
ObjectBufferParameters.Set(RHICmdList, ShaderRHI, *(Scene->DistanceFieldSceneData.ObjectBuffers), Scene->DistanceFieldSceneData.NumObjectsInBuffer);
|
|
CulledObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers);
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
|
|
// Shader assumes max 6
|
|
check(View.ViewFrustum.Planes.Num() <= 6);
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumConvexHullPlanes, View.ViewFrustum.Planes.Num());
|
|
SetShaderValueArray(RHICmdList, ShaderRHI, ViewFrustumConvexHull, View.ViewFrustum.Planes.GetData(), View.ViewFrustum.Planes.Num());
|
|
SetShaderValue(RHICmdList, ShaderRHI, ObjectBoundingGeometryIndexCount, StencilingGeometry::GLowPolyStencilSphereIndexBuffer.GetIndexCount());
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, const FScene* Scene)
|
|
{
|
|
ObjectBufferParameters.UnsetParameters(RHICmdList, GetComputeShader(), *(Scene->DistanceFieldSceneData.ObjectBuffers));
|
|
CulledObjectParameters.UnsetParameters(RHICmdList, GetComputeShader());
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[6];
|
|
OutUAVs[0] = GAOCulledObjectBuffers.Buffers.ObjectIndirectArguments.UAV;
|
|
OutUAVs[1] = GAOCulledObjectBuffers.Buffers.Bounds.UAV;
|
|
OutUAVs[2] = GAOCulledObjectBuffers.Buffers.Data.UAV;
|
|
OutUAVs[3] = GAOCulledObjectBuffers.Buffers.BoxBounds.UAV;
|
|
OutUAVs[4] = Scene->DistanceFieldSceneData.ObjectBuffers->Data.UAV;
|
|
OutUAVs[5] = Scene->DistanceFieldSceneData.ObjectBuffers->Bounds.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar)
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ObjectBufferParameters;
|
|
Ar << CulledObjectParameters;
|
|
Ar << AOParameters;
|
|
Ar << NumConvexHullPlanes;
|
|
Ar << ViewFrustumConvexHull;
|
|
Ar << ObjectBoundingGeometryIndexCount;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FDistanceFieldObjectBufferParameters ObjectBufferParameters;
|
|
FDistanceFieldCulledObjectBufferParameters CulledObjectParameters;
|
|
FAOParameters AOParameters;
|
|
FShaderParameter NumConvexHullPlanes;
|
|
FShaderParameter ViewFrustumConvexHull;
|
|
FShaderParameter ObjectBoundingGeometryIndexCount;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCullObjectsForViewCS,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("CullObjectsForViewCS"),SF_Compute);
|
|
|
|
void CullObjectsToView(FRHICommandListImmediate& RHICmdList, FScene* Scene, const FViewInfo& View, const FDistanceFieldAOParameters& Parameters, FDistanceFieldObjectBufferResource& CulledObjectBuffers)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, ObjectFrustumCulling);
|
|
|
|
if (!CulledObjectBuffers.IsInitialized()
|
|
|| CulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer
|
|
|| CulledObjectBuffers.Buffers.MaxObjects > 3 * Scene->DistanceFieldSceneData.NumObjectsInBuffer)
|
|
{
|
|
CulledObjectBuffers.Buffers.MaxObjects = Scene->DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4;
|
|
CulledObjectBuffers.ReleaseResource();
|
|
CulledObjectBuffers.InitResource();
|
|
}
|
|
CulledObjectBuffers.Buffers.AcquireTransientResource();
|
|
|
|
{
|
|
ClearUAV(RHICmdList, CulledObjectBuffers.Buffers.ObjectIndirectArguments, 0);
|
|
|
|
TShaderMapRef<FCullObjectsForViewCS> ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, Scene, View, Parameters);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(Scene->DistanceFieldSceneData.NumObjectsInBuffer, UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, Scene);
|
|
}
|
|
}
|
|
|
|
/** */
|
|
class FBuildTileConesCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FBuildTileConesCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), GDistanceFieldAOTileSizeX);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), GDistanceFieldAOTileSizeY);
|
|
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
|
|
|
|
// To reduce shader compile time of compute shaders with shared memory, doesn't have an impact on generated code with current compiler (June 2010 DX SDK)
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization);
|
|
}
|
|
|
|
FBuildTileConesCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
SceneTextureParameters.Bind(Initializer);
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
TileConeAxisAndCos.Bind(Initializer.ParameterMap, TEXT("TileConeAxisAndCos"));
|
|
TileConeDepthRanges.Bind(Initializer.ParameterMap, TEXT("TileConeDepthRanges"));
|
|
NumGroups.Bind(Initializer.ParameterMap, TEXT("NumGroups"));
|
|
ViewDimensionsParameter.Bind(Initializer.ParameterMap, TEXT("ViewDimensions"));
|
|
DistanceFieldNormalTexture.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalTexture"));
|
|
DistanceFieldNormalSampler.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalSampler"));
|
|
}
|
|
|
|
FBuildTileConesCS()
|
|
{
|
|
}
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, FSceneRenderTargetItem& DistanceFieldNormal, FScene* Scene, FVector2D NumGroupsValue, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
SceneTextureParameters.Set(RHICmdList, ShaderRHI, View.FeatureLevel, ESceneTextureSetupMode::All);
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = TileIntersectionResources->TileConeAxisAndCos.UAV;
|
|
OutUAVs[1] = TileIntersectionResources->TileConeDepthRanges.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
|
|
TileConeAxisAndCos.SetBuffer(RHICmdList, ShaderRHI, TileIntersectionResources->TileConeAxisAndCos);
|
|
TileConeDepthRanges.SetBuffer(RHICmdList, ShaderRHI, TileIntersectionResources->TileConeDepthRanges);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, ViewDimensionsParameter, View.ViewRect);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue);
|
|
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
ShaderRHI,
|
|
DistanceFieldNormalTexture,
|
|
DistanceFieldNormalSampler,
|
|
TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
|
|
DistanceFieldNormal.ShaderResourceTexture
|
|
);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
|
|
{
|
|
TileConeAxisAndCos.UnsetUAV(RHICmdList, GetComputeShader());
|
|
TileConeDepthRanges.UnsetUAV(RHICmdList, GetComputeShader());
|
|
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = TileIntersectionResources->TileConeAxisAndCos.UAV;
|
|
OutUAVs[1] = TileIntersectionResources->TileConeDepthRanges.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar)
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << SceneTextureParameters;
|
|
Ar << AOParameters;
|
|
Ar << TileConeAxisAndCos;
|
|
Ar << TileConeDepthRanges;
|
|
Ar << NumGroups;
|
|
Ar << ViewDimensionsParameter;
|
|
Ar << DistanceFieldNormalTexture;
|
|
Ar << DistanceFieldNormalSampler;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FSceneTextureShaderParameters SceneTextureParameters;
|
|
FAOParameters AOParameters;
|
|
FRWShaderParameter TileConeAxisAndCos;
|
|
FRWShaderParameter TileConeDepthRanges;
|
|
FShaderParameter ViewDimensionsParameter;
|
|
FShaderParameter NumGroups;
|
|
FShaderResourceParameter DistanceFieldNormalTexture;
|
|
FShaderResourceParameter DistanceFieldNormalSampler;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FBuildTileConesCS,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("BuildTileConesMain"),SF_Compute);
|
|
|
|
/** */
|
|
class FObjectCullVS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FObjectCullVS,Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform);
|
|
}
|
|
|
|
FObjectCullVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FGlobalShader(Initializer)
|
|
{
|
|
ObjectParameters.Bind(Initializer.ParameterMap);
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
ConservativeRadiusScale.Bind(Initializer.ParameterMap, TEXT("ConservativeRadiusScale"));
|
|
}
|
|
|
|
FObjectCullVS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader();
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
|
|
ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers);
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
|
|
const int32 NumRings = StencilingGeometry::GLowPolyStencilSphereVertexBuffer.GetNumRings();
|
|
const float RadiansPerRingSegment = PI / (float)NumRings;
|
|
|
|
// Boost the effective radius so that the edges of the sphere approximation lie on the sphere, instead of the vertices
|
|
const float ConservativeRadiusScaleValue = 1.0f / FMath::Cos(RadiansPerRingSegment);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, ConservativeRadiusScale, ConservativeRadiusScaleValue);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ObjectParameters;
|
|
Ar << AOParameters;
|
|
Ar << ConservativeRadiusScale;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FDistanceFieldCulledObjectBufferParameters ObjectParameters;
|
|
FAOParameters AOParameters;
|
|
FShaderParameter ConservativeRadiusScale;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FObjectCullVS,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("ObjectCullVS"),SF_Vertex);
|
|
|
|
template <bool bCountingPass>
|
|
class TObjectCullPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(TObjectCullPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && RHISupportsPixelShaderUAVs(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
FTileIntersectionParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
|
|
|
|
OutEnvironment.SetDefine(TEXT("DOWNSAMPLE_FACTOR"), GAODownsampleFactor);
|
|
OutEnvironment.SetDefine(TEXT("SCATTER_CULLING_COUNT_PASS"), bCountingPass ? 1 : 0);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
TObjectCullPS() {}
|
|
|
|
/** Initialization constructor. */
|
|
TObjectCullPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
ObjectParameters.Bind(Initializer.ParameterMap);
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
TileIntersectionParameters.Bind(Initializer.ParameterMap);
|
|
TileConeAxisAndCos.Bind(Initializer.ParameterMap, TEXT("TileConeAxisAndCos"));
|
|
TileConeDepthRanges.Bind(Initializer.ParameterMap, TEXT("TileConeDepthRanges"));
|
|
NumGroups.Bind(Initializer.ParameterMap, TEXT("NumGroups"));
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FVector2D NumGroupsValue, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers);
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
SetSRVParameter(RHICmdList, ShaderRHI, TileConeAxisAndCos, TileIntersectionResources->TileConeAxisAndCos.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, TileConeDepthRanges, TileIntersectionResources->TileConeDepthRanges.SRV);
|
|
TileIntersectionParameters.Set(RHICmdList, ShaderRHI, *TileIntersectionResources);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue);
|
|
}
|
|
|
|
void GetUAVs(const FSceneView& View, TArray<FUnorderedAccessViewRHIParamRef>& UAVs)
|
|
{
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
TileIntersectionParameters.GetUAVs(*TileIntersectionResources, UAVs);
|
|
check(UAVs.Num() > 0);
|
|
}
|
|
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ObjectParameters;
|
|
Ar << AOParameters;
|
|
Ar << TileIntersectionParameters;
|
|
Ar << TileConeAxisAndCos;
|
|
Ar << TileConeDepthRanges;
|
|
Ar << NumGroups;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FDistanceFieldCulledObjectBufferParameters ObjectParameters;
|
|
FAOParameters AOParameters;
|
|
FTileIntersectionParameters TileIntersectionParameters;
|
|
FShaderResourceParameter TileConeAxisAndCos;
|
|
FShaderResourceParameter TileConeDepthRanges;
|
|
FShaderParameter NumGroups;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(template<>,TObjectCullPS<true>,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("ObjectCullPS"),SF_Pixel);
|
|
IMPLEMENT_SHADER_TYPE(template<>,TObjectCullPS<false>,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("ObjectCullPS"),SF_Pixel);
|
|
|
|
const uint32 ComputeStartOffsetGroupSize = 64;
|
|
|
|
/** */
|
|
class FComputeCulledTilesStartOffsetCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FComputeCulledTilesStartOffsetCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Parameters.Platform) && IsUsingDistanceFields(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters,OutEnvironment);
|
|
FTileIntersectionParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
|
|
|
|
OutEnvironment.SetDefine(TEXT("COMPUTE_START_OFFSET_GROUP_SIZE"), ComputeStartOffsetGroupSize);
|
|
}
|
|
|
|
FComputeCulledTilesStartOffsetCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
ObjectParameters.Bind(Initializer.ParameterMap);
|
|
TileIntersectionParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
FComputeCulledTilesStartOffsetCS()
|
|
{
|
|
}
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
|
|
ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers);
|
|
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
TArray<FUnorderedAccessViewRHIParamRef> UAVs;
|
|
TileIntersectionParameters.GetUAVs(*TileIntersectionResources, UAVs);
|
|
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EComputeToCompute, UAVs.GetData(), UAVs.Num());
|
|
|
|
TileIntersectionParameters.Set(RHICmdList, ShaderRHI, *TileIntersectionResources);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
|
|
{
|
|
FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
TileIntersectionParameters.UnsetParameters(RHICmdList, GetComputeShader());
|
|
|
|
TArray<FUnorderedAccessViewRHIParamRef> UAVs;
|
|
TileIntersectionParameters.GetUAVs(*TileIntersectionResources, UAVs);
|
|
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, UAVs.GetData(), UAVs.Num());
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ObjectParameters;
|
|
Ar << TileIntersectionParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FDistanceFieldCulledObjectBufferParameters ObjectParameters;
|
|
FTileIntersectionParameters TileIntersectionParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FComputeCulledTilesStartOffsetCS,TEXT("/Engine/Private/DistanceFieldObjectCulling.usf"),TEXT("ComputeCulledTilesStartOffsetCS"),SF_Compute);
|
|
|
|
template<bool bCountingPass>
|
|
void ScatterTilesToObjects(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, FIntPoint TileListGroupSize, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
TShaderMapRef<FObjectCullVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<TObjectCullPS<bCountingPass>> PixelShader(View.ShaderMap);
|
|
|
|
TArray<FUnorderedAccessViewRHIParamRef> UAVs;
|
|
PixelShader->GetUAVs(View, UAVs);
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToGfx, UAVs.GetData(), UAVs.Num());
|
|
|
|
FRHIRenderPassInfo RPInfo(UAVs.Num(), UAVs.GetData());
|
|
if (GRHIRequiresRenderTargetForPixelShaderUAVs)
|
|
{
|
|
TRefCountPtr<IPooledRenderTarget> Dummy;
|
|
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(TileListGroupSize, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, Dummy, TEXT("Dummy"));
|
|
|
|
RPInfo.ColorRenderTargets[0].Action = ERenderTargetActions::DontLoad_DontStore;
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = -1;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = 0;
|
|
RPInfo.ColorRenderTargets[0].RenderTarget = Dummy->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("ScatterTilesToObjects"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, TileListGroupSize.X, TileListGroupSize.Y, 1.0f);
|
|
|
|
// Render backfaces since camera may intersect
|
|
GraphicsPSOInit.RasterizerState = View.bReverseCulling ? TStaticRasterizerState<FM_Solid, CM_CW>::GetRHI() : TStaticRasterizerState<FM_Solid, CM_CCW>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View, Parameters);
|
|
PixelShader->SetParameters(RHICmdList, View, FVector2D(TileListGroupSize.X, TileListGroupSize.Y), Parameters);
|
|
|
|
RHICmdList.SetStreamSource(0, StencilingGeometry::GLowPolyStencilSphereVertexBuffer.VertexBufferRHI, 0);
|
|
|
|
RHICmdList.DrawIndexedPrimitiveIndirect(
|
|
StencilingGeometry::GLowPolyStencilSphereIndexBuffer.IndexBufferRHI,
|
|
GAOCulledObjectBuffers.Buffers.ObjectIndirectArguments.Buffer,
|
|
0);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
// #todo-renderpasses Remove once SetRenderTargets is completely removed.
|
|
UnbindRenderTargets(RHICmdList);
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToCompute, UAVs.GetData(), UAVs.Num());
|
|
}
|
|
|
|
FIntPoint GetTileListGroupSizeForView(const FViewInfo& View)
|
|
{
|
|
return FIntPoint(
|
|
FMath::DivideAndRoundUp(FMath::Max(View.ViewRect.Size().X / GAODownsampleFactor, 1), GDistanceFieldAOTileSizeX),
|
|
FMath::DivideAndRoundUp(FMath::Max(View.ViewRect.Size().Y / GAODownsampleFactor, 1), GDistanceFieldAOTileSizeY));
|
|
}
|
|
|
|
void BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Scene, TArray<FViewInfo>& Views, FSceneRenderTargetItem& DistanceFieldNormal, const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, BuildTileList);
|
|
UnbindRenderTargets(RHICmdList);
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
const FIntPoint TileListGroupSize = GetTileListGroupSizeForView(View);
|
|
|
|
FTileIntersectionResources*& TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources;
|
|
|
|
if (!TileIntersectionResources
|
|
|| !TileIntersectionResources->IsInitialized()
|
|
|| !TileIntersectionResources->HasAllocatedEnoughFor(TileListGroupSize, Scene->DistanceFieldSceneData.NumObjectsInBuffer)
|
|
|| GFastVRamConfig.bDirty )
|
|
{
|
|
if (TileIntersectionResources)
|
|
{
|
|
TileIntersectionResources->ReleaseResource();
|
|
}
|
|
else
|
|
{
|
|
TileIntersectionResources = new FTileIntersectionResources(!IsMetalPlatform(GShaderPlatformForFeatureLevel[View.FeatureLevel]));
|
|
}
|
|
|
|
TileIntersectionResources->SetupParameters(TileListGroupSize, Scene->DistanceFieldSceneData.NumObjectsInBuffer);
|
|
TileIntersectionResources->InitResource();
|
|
}
|
|
TileIntersectionResources->AcquireTransientResource();
|
|
|
|
if (GAOScatterTileCulling)
|
|
{
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, BuildTileCones);
|
|
TShaderMapRef<FBuildTileConesCS> ComputeShader(View.ShaderMap);
|
|
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View, DistanceFieldNormal, Scene, FVector2D(TileListGroupSize.X, TileListGroupSize.Y), Parameters);
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, TileListGroupSize.X, TileListGroupSize.Y, 1);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList, View);
|
|
}
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, CountTileObjectIntersections);
|
|
|
|
// Start at 0 tiles per object
|
|
ClearUAV(RHICmdList, TileIntersectionResources->NumCulledTilesArray, 0);
|
|
|
|
// Rasterize object bounding shapes and intersect with screen tiles to compute how many tiles intersect each object
|
|
ScatterTilesToObjects<true>(RHICmdList, View, TileListGroupSize, Parameters);
|
|
}
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, ComputeStartOffsets);
|
|
// Start at 0 threadgroups
|
|
ClearUAV(RHICmdList, TileIntersectionResources->ObjectTilesIndirectArguments, 0);
|
|
|
|
// Accumulate how many cone trace threadgroups we should dispatch, and also compute the start offset for each object's culled tile data
|
|
TShaderMapRef<FComputeCulledTilesStartOffsetCS> ComputeShader(View.ShaderMap);
|
|
const uint32 GroupSize = FMath::DivideAndRoundUp<uint32>(Scene->DistanceFieldSceneData.NumObjectsInBuffer, ComputeStartOffsetGroupSize);
|
|
// Must write to RWObjectTilesIndirectArguments
|
|
check(GroupSize != 0);
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View);
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, GroupSize, 1, 1);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList, View);
|
|
}
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, CullTilesToObjects);
|
|
|
|
// Start at 0 tiles per object
|
|
ClearUAV(RHICmdList, TileIntersectionResources->NumCulledTilesArray, 0);
|
|
|
|
// Rasterize object bounding shapes and intersect with screen tiles, and write out intersecting tile indices for the cone tracing pass
|
|
ScatterTilesToObjects<false>(RHICmdList, View, TileListGroupSize, Parameters);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ensure(0);
|
|
}
|
|
}
|
|
}
|