You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- this fixes a number of crashes and issue with heightfields missing from global distance field when heightfield shadows are enabled.
- Context:
- Heightfields are used by two techniques using different approaches:
- Global Distance Field (r.AOGlobalDistanceField.Heightfield) - heightfields are composed one by one into Global SDF so there's no need for bindless resources or atlas.
- Height Field Shadows (r.HeightFieldShadowing) - since all heightfields data must be accessible in the same dispatch, heightfields descriptiors are stored in structured buffers (HeightFieldObjectBuffers) and textures are copied to an atlas (GHeightFieldTextureAtlas/GHFVisibilityTextureAtlas).
- FDistanceFieldSceneData::HeightfieldPrimitives is an array of relevant heighfield primitives.
- For each primitive, DistanceFieldInstanceIndices contains the index of the corresponding entry in HeightfieldPrimitives array.
- The same DistanceFieldInstanceIndices is also used to manage distance fields (there's an assumption that a primitive can have a distance field or a height field, but not both).
- The codepath to manage the HeightFieldObjectBuffers and GHeightFieldTextureAtlas/GHFVisibilityTextureAtlas is only enabled when ShouldPrepareHeightFieldScene() returns true.
- There's limited space in the atlas so it's not guaranteed that every loaded heightfield fits in the atlas.
- Issues with existing approach:
- When the codepath to manage HeightFieldObjectBuffers/Atlases is enabled, only the heighfields that fit in the atlas are added to FDistanceFieldSceneData::HeightfieldPrimitives.
- this means that in some cases not every loaded heighfield will be composed into the global distance field (since only primitives in HeightfieldPrimitives are included).
- there are also a few bugs with the code that can result in crashes.
- Heighfields that fail the inital allocation are not added to HeightfieldPrimitives even after space becomes available in the atlas.
- the atlas itself correctly retries to fit failed allocations when space becomes available, however the higher level managment code doesn't handle this.
- Changes:
- all heightfield primitives are added to FDistanceFieldSceneData::HeightfieldPrimitives regardless of whether they fit in atlas or not.
- this way all heightfields will be included in global distance field
- added a new field, bInAtlas, to entries in HeightFieldObjectBuffers.
- during Height Field Shadows culling pass, heightfields not present in atlas are skipped.
- significantly refactored relevant codepaths to simplify logic.
#rb Krzysztof.Narkowicz, Jian.Ru
#preflight 6372c0ef953c19d4353ad211
[CL 23131399 by tiago costa in ue5-main branch]
219 lines
7.6 KiB
C++
219 lines
7.6 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DistanceFieldLightingShared.h
|
|
=============================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "RHI.h"
|
|
#include "RenderResource.h"
|
|
#include "ShaderParameters.h"
|
|
#include "RenderUtils.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "DistanceFieldAtlas.h"
|
|
#include "Templates/UniquePtr.h"
|
|
#include "SceneRendering.h"
|
|
#include "ScenePrivate.h"
|
|
|
|
class FLightSceneProxy;
|
|
class FMaterialRenderProxy;
|
|
class FPrimitiveSceneInfo;
|
|
class FSceneRenderer;
|
|
class FShaderParameterMap;
|
|
class FViewInfo;
|
|
class FDistanceFieldSceneData;
|
|
|
|
DECLARE_LOG_CATEGORY_EXTERN(LogDistanceField, Log, All);
|
|
|
|
/** Tile sized used for most AO compute shaders. */
|
|
extern int32 GDistanceFieldAOTileSizeX;
|
|
extern int32 GDistanceFieldAOTileSizeY;
|
|
extern int32 GAverageObjectsPerShadowCullTile;
|
|
extern int32 GAverageHeightFieldObjectsPerShadowCullTile;
|
|
|
|
extern bool UseDistanceFieldAO();
|
|
extern bool UseAOObjectDistanceField();
|
|
|
|
enum EDistanceFieldPrimitiveType
|
|
{
|
|
DFPT_SignedDistanceField,
|
|
DFPT_HeightField,
|
|
DFPT_Num
|
|
};
|
|
|
|
// Must match equivalent shader defines
|
|
static const int32 GDistanceFieldObjectDataStride = 10;
|
|
static const int32 GDistanceFieldObjectBoundsStride = 3;
|
|
|
|
static const int32 GHeightFieldObjectDataStride = 7;
|
|
static const int32 GHeightFieldObjectBoundsStride = 3;
|
|
|
|
template <EDistanceFieldPrimitiveType PrimitiveType>
|
|
class TDistanceFieldObjectBuffers
|
|
{
|
|
public:
|
|
|
|
static int32 ObjectDataStride;
|
|
static int32 ObjectBoundsStride;
|
|
|
|
TRefCountPtr<FRDGPooledBuffer> Bounds;
|
|
TRefCountPtr<FRDGPooledBuffer> Data;
|
|
|
|
TDistanceFieldObjectBuffers()
|
|
{
|
|
}
|
|
|
|
void Initialize();
|
|
|
|
void Release()
|
|
{
|
|
Bounds = nullptr;
|
|
Data = nullptr;
|
|
}
|
|
|
|
size_t GetSizeBytes() const
|
|
{
|
|
return TryGetSize(Bounds) + TryGetSize(Data);
|
|
}
|
|
};
|
|
|
|
class FDistanceFieldObjectBuffers : public TDistanceFieldObjectBuffers<DFPT_SignedDistanceField> {};
|
|
class FHeightFieldObjectBuffers : public TDistanceFieldObjectBuffers<DFPT_HeightField> {};
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FDistanceFieldObjectBufferParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float4>, SceneObjectBounds)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float4>, SceneObjectData)
|
|
SHADER_PARAMETER(uint32, NumSceneObjects)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float4>, SceneHeightfieldObjectBounds)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float4>, SceneHeightfieldObjectData)
|
|
SHADER_PARAMETER(uint32, NumSceneHeightfieldObjects)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FDistanceFieldAtlasParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float4>, SceneDistanceFieldAssetData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, DistanceFieldIndirectionTable)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<float4>, DistanceFieldIndirection2Table)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture3D<float4>, DistanceFieldIndirectionAtlas)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture3D, DistanceFieldBrickTexture)
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, DistanceFieldSampler)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldBrickSize)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldUniqueDataBrickSize)
|
|
SHADER_PARAMETER(FIntVector, DistanceFieldBrickAtlasSizeInBricks)
|
|
SHADER_PARAMETER(FIntVector, DistanceFieldBrickAtlasMask)
|
|
SHADER_PARAMETER(FIntVector, DistanceFieldBrickAtlasSizeLog2)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldBrickAtlasTexelSize)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldBrickAtlasHalfTexelSize)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldBrickOffsetToAtlasUVScale)
|
|
SHADER_PARAMETER(FVector3f, DistanceFieldUniqueDataBrickSizeInAtlasTexels)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FHeightFieldAtlasParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, HeightFieldTexture)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, HFVisibilityTexture)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
namespace DistanceField
|
|
{
|
|
constexpr uint32 MinPrimitiveModifiedBoundsAllocation = 16 * 1024;
|
|
|
|
RENDERER_API FDistanceFieldObjectBufferParameters SetupObjectBufferParameters(FRDGBuilder& GraphBuilder, const FDistanceFieldSceneData& DistanceFieldSceneData);
|
|
RENDERER_API FDistanceFieldAtlasParameters SetupAtlasParameters(FRDGBuilder& GraphBuilder, const FDistanceFieldSceneData& DistanceFieldSceneData);
|
|
};
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FDistanceFieldCulledObjectBufferParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWObjectIndirectArguments)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWCulledObjectIndices)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, ObjectIndirectArguments)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, CulledObjectIndices)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
extern void AllocateDistanceFieldCulledObjectBuffers(
|
|
FRDGBuilder& GraphBuilder,
|
|
uint32 MaxObjects,
|
|
FRDGBufferRef& OutObjectIndirectArguments,
|
|
FDistanceFieldCulledObjectBufferParameters& OutParameters);
|
|
|
|
class FCPUUpdatedBuffer
|
|
{
|
|
public:
|
|
|
|
EPixelFormat Format;
|
|
int32 Stride;
|
|
int32 MaxElements;
|
|
|
|
// Volatile must be written every frame before use. Supports multiple writes per frame on PS4, unlike Dynamic.
|
|
bool bVolatile;
|
|
|
|
FBufferRHIRef Buffer;
|
|
FShaderResourceViewRHIRef BufferSRV;
|
|
|
|
FCPUUpdatedBuffer()
|
|
{
|
|
Format = PF_A32B32G32R32F;
|
|
Stride = 1;
|
|
MaxElements = 0;
|
|
bVolatile = true;
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
if (MaxElements > 0 && Stride > 0)
|
|
{
|
|
FRHIResourceCreateInfo CreateInfo(TEXT("FCPUUpdatedBuffer"));
|
|
Buffer = RHICreateVertexBuffer(MaxElements * Stride * GPixelFormats[Format].BlockBytes, (bVolatile ? BUF_Volatile : BUF_Dynamic) | BUF_ShaderResource, CreateInfo);
|
|
BufferSRV = RHICreateShaderResourceView(Buffer, GPixelFormats[Format].BlockBytes, Format);
|
|
}
|
|
}
|
|
|
|
void Release()
|
|
{
|
|
Buffer.SafeRelease();
|
|
BufferSRV.SafeRelease();
|
|
}
|
|
|
|
size_t GetSizeBytes() const
|
|
{
|
|
return MaxElements * Stride * GPixelFormats[Format].BlockBytes;
|
|
}
|
|
};
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FLightTileIntersectionParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWShadowTileNumCulledObjects)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWShadowTileStartOffsets)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWNextStartOffset)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, RWShadowTileArrayData)
|
|
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, ShadowTileNumCulledObjects)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, ShadowTileStartOffsets)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, NextStartOffset)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, ShadowTileArrayData)
|
|
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, HeightfieldShadowTileNumCulledObjects)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, HeightfieldShadowTileStartOffsets)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<uint>, HeightfieldShadowTileArrayData)
|
|
|
|
SHADER_PARAMETER(FIntPoint, ShadowTileListGroupSize)
|
|
SHADER_PARAMETER(uint32, ShadowMaxObjectsPerTile)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
extern void CullDistanceFieldObjectsForLight(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
const FLightSceneProxy* LightSceneProxy,
|
|
EDistanceFieldPrimitiveType PrimitiveType,
|
|
const FMatrix& WorldToShadowValue,
|
|
int32 NumPlanes,
|
|
const FPlane* PlaneData,
|
|
const FVector& PrePlaneTranslation,
|
|
const FVector4f& ShadowBoundingSphere,
|
|
float ShadowBoundingRadius,
|
|
bool bCullingForDirectShadowing,
|
|
bool bCullHeighfieldsNotInAtlas,
|
|
const FDistanceFieldObjectBufferParameters& ObjectBufferParameters,
|
|
FDistanceFieldCulledObjectBufferParameters& CulledObjectBufferParameters,
|
|
FLightTileIntersectionParameters& LightTileIntersectionParameters);
|
|
|
|
extern bool SupportsDistanceFieldAO(ERHIFeatureLevel::Type FeatureLevel, EShaderPlatform ShaderPlatform);
|