548 lines
20 KiB
C++
548 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "SceneManagement.h"
|
|
#include "SceneView.h"
|
|
#include "VirtualShadowMapDefinitions.h"
|
|
#include "ScreenPass.h"
|
|
|
|
struct FMinimalSceneTextures;
|
|
struct FSortedLightSetSceneInfo;
|
|
struct FNaniteVisibilityQuery;
|
|
class FViewInfo;
|
|
class FProjectedShadowInfo;
|
|
class FVisibleLightInfo;
|
|
class FVirtualShadowMapCacheEntry;
|
|
class FVirtualShadowMapArrayCacheManager;
|
|
struct FSortedLightSetSceneInfo;
|
|
class FVirtualShadowMapClipmap;
|
|
struct FScreenPassTexture;
|
|
struct FSingleLayerWaterPrePassResult;
|
|
class FNaniteVisibilityResults;
|
|
class FSceneRenderer;
|
|
class FSceneUniformBuffer;
|
|
struct FShaderCompilerEnvironment;
|
|
struct FFrontLayerTranslucencyData;
|
|
class FSceneInstanceCullingQuery;
|
|
class FInstanceCullingManager;
|
|
struct FPersistentViewId;
|
|
|
|
namespace Froxel
|
|
{
|
|
class FRenderer;
|
|
}
|
|
|
|
namespace Nanite
|
|
{
|
|
struct FPackedView;
|
|
class FPackedViewArray;
|
|
struct FRasterResults;
|
|
}
|
|
|
|
|
|
// Generally only one pass, but we collect this to handle exceptional cases
|
|
struct FNaniteVirtualShadowMapRenderPass
|
|
{
|
|
FSceneInstanceCullingQuery *SceneInstanceCullingQuery = nullptr;
|
|
TArray<FProjectedShadowInfo*, SceneRenderingAllocator> Shadows;
|
|
uint32 TotalPrimaryViews = 0u;
|
|
uint32 MaxCullingViews = 0u;
|
|
Nanite::FPackedViewArray* VirtualShadowMapViews = nullptr;
|
|
};
|
|
|
|
inline bool IsSinglePageVirtualShadowMap(int32 VirtualShadowMapId)
|
|
{
|
|
return VirtualShadowMapId < int32(VSM_MAX_SINGLE_PAGE_SHADOW_MAPS);
|
|
}
|
|
|
|
bool DoesVSMWantFroxels(EShaderPlatform ShaderPlatform);
|
|
|
|
bool IsVirtualShadowMapLocalReceiverMaskEnabled();
|
|
|
|
class FVirtualShadowMap
|
|
{
|
|
public:
|
|
// PageSize * Level0DimPagesXY defines the virtual address space, e.g., 128x128 = 16k
|
|
|
|
// 128x128 = 16k
|
|
static constexpr uint32 PageSize = VSM_PAGE_SIZE;
|
|
static constexpr uint32 PageSizeMask = VSM_PAGE_SIZE_MASK;
|
|
static constexpr uint32 Log2PageSize = VSM_LOG2_PAGE_SIZE;
|
|
static constexpr uint32 Level0DimPagesXY = VSM_LEVEL0_DIM_PAGES_XY;
|
|
static constexpr uint32 Log2Level0DimPagesXY = VSM_LOG2_LEVEL0_DIM_PAGES_XY;
|
|
static constexpr uint32 MaxMipLevels = VSM_MAX_MIP_LEVELS;
|
|
static constexpr uint32 VirtualMaxResolutionXY = VSM_VIRTUAL_MAX_RESOLUTION_XY;
|
|
static constexpr uint32 RasterWindowPages = VSM_RASTER_WINDOW_PAGES;
|
|
|
|
static constexpr uint32 PhysicalPageAddressBits = 16U;
|
|
static constexpr uint32 MaxPhysicalTextureDimPages = 1U << PhysicalPageAddressBits;
|
|
static constexpr uint32 MaxPhysicalTextureDimTexels = MaxPhysicalTextureDimPages * PageSize;
|
|
|
|
static constexpr uint32 NumHZBLevels = Log2PageSize;
|
|
|
|
|
|
static_assert(MaxMipLevels <= 8, ">8 mips requires more PageFlags bits. See VSM_PAGE_FLAGS_BITS_PER_HMIP in PageAccessCommon.ush");
|
|
|
|
// TODO: Currently only used for these constants... probably rename the cache structure to virtual shadow map now instead
|
|
private:
|
|
FVirtualShadowMap() {}
|
|
};
|
|
|
|
// Useful data for both the page mapping shader and the projection shader
|
|
// as well as cached shadow maps
|
|
struct FVirtualShadowMapProjectionShaderData
|
|
{
|
|
FMatrix44f ShadowViewToClipMatrix;
|
|
FMatrix44f TranslatedWorldToShadowUVMatrix;
|
|
FMatrix44f TranslatedWorldToShadowUVNormalMatrix;
|
|
|
|
FVector3f LightDirection;
|
|
uint32 LightType = ELightComponentType::LightType_Directional;
|
|
|
|
FVector3f PreViewTranslationHigh;
|
|
float LightRadius;
|
|
|
|
FVector3f PreViewTranslationLow;
|
|
// Slightly different meaning for clipmaps (includes camera pixel size scaling stuff) and local lights (raw bias)
|
|
float ResolutionLodBias = 0.0f;
|
|
|
|
// TODO: There are more local lights than directional
|
|
// We should move the directional-specific stuff out to its own structure.
|
|
FVector3f NegativeClipmapWorldOriginLWCOffset; // Shares the LWCTile with PreViewTranslation
|
|
float LightSourceRadius;
|
|
|
|
FIntPoint ClipmapCornerRelativeOffset = FIntPoint(0, 0);
|
|
|
|
// Packed ClipmapLevel and ClipmapLevelCountRemaining, -1 if not a clipmap
|
|
// "Absolute" level, can be negative. Max_int32 if not a clipmap.
|
|
// Remaining levels, relative to this one. Negative if not a clipmap.
|
|
int32 ClipmapLevel_ClipmapLevelCountRemaining = -1;
|
|
|
|
// See PackCullingViewId for details
|
|
int32 PackedCullingViewId = 0u;
|
|
|
|
uint32 Flags = 0U;
|
|
// This clipmap level should allow WPO if this value is less than InstanceWPODisableDistanceSquared
|
|
float ClipmapLevelWPODistanceDisableThresholdSquared = 0.0f;
|
|
float TexelDitherScale;
|
|
|
|
uint32 MinMipLevel = 0u;
|
|
// Note: Seems the FMatrix forces 16-byte alignment so pad as needed.
|
|
|
|
static uint32 PackCullingViewId(int32 SceneRendererPrimaryViewId, const FPersistentViewId& PersistentViewId);
|
|
};
|
|
static_assert(sizeof(FVirtualShadowMapProjectionShaderData) == VSM_PSD_STRIDE, "FVirtualShadowMapProjectionShaderData does not match size in shader. See VirtualShadowMapProjectionStructs.ush.");
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FVirtualShadowMapPerViewParameters, )
|
|
// Light grid with only the lights that have VSMs present
|
|
// Still references the original indices from the global light grid
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, LightGridData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, NumCulledLightsGrid)
|
|
SHADER_PARAMETER(uint32, MaxLightGridEntryIndex)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FVirtualShadowMapUniformParameters, )
|
|
SHADER_PARAMETER(uint32, NumFullShadowMaps)
|
|
SHADER_PARAMETER(uint32, NumSinglePageShadowMaps)
|
|
SHADER_PARAMETER(uint32, MaxPhysicalPages)
|
|
SHADER_PARAMETER(uint32, NumShadowMapSlots)
|
|
// Set to 0 if separate static caching is disabled
|
|
SHADER_PARAMETER(uint32, StaticCachedArrayIndex)
|
|
// Set to 0 if separate static caching is disabled OR separate dynamic HZB is disabled
|
|
SHADER_PARAMETER(uint32, StaticHZBArrayIndex)
|
|
|
|
// use to map linear index to x,y page coord
|
|
SHADER_PARAMETER(uint32, PhysicalPageRowMask)
|
|
SHADER_PARAMETER(uint32, PhysicalPageRowShift)
|
|
SHADER_PARAMETER(uint32, PackedShadowMaskMaxLightCount)
|
|
SHADER_PARAMETER(FVector4f, RecPhysicalPoolSize)
|
|
SHADER_PARAMETER(FIntPoint, PhysicalPoolSize)
|
|
SHADER_PARAMETER(FIntPoint, PhysicalPoolSizePages)
|
|
// TODO: verify whether this turns into 2 loads or one
|
|
SHADER_PARAMETER(uint32, PageTableRowShift)
|
|
SHADER_PARAMETER(uint32, PageTableRowMask)
|
|
// xy == PageTableTextureSize, zw == 1.0f/PageTableTextureSize
|
|
SHADER_PARAMETER(FVector4f, PageTableTextureSizeInvSize)
|
|
|
|
// Set to 1 if r.Shadow.Virtual.NonNanite.IncludeInCoarsePages is set to 0 in order to signal that we want to use the legacy path for just excluding non-nanite
|
|
SHADER_PARAMETER(uint32, bExcludeNonNaniteFromCoarsePages)
|
|
SHADER_PARAMETER(float, CoarsePagePixelThresholdDynamic)
|
|
SHADER_PARAMETER(float, CoarsePagePixelThresholdStatic)
|
|
SHADER_PARAMETER(float, CoarsePagePixelThresholdDynamicNanite)
|
|
|
|
// For shadow page age calculations
|
|
SHADER_PARAMETER(uint32, SceneFrameNumber)
|
|
|
|
SHADER_PARAMETER(float, GlobalResolutionLodBias)
|
|
SHADER_PARAMETER(int32, bEnableReceiverMasks)
|
|
SHADER_PARAMETER(int32, MipModeLocal)
|
|
|
|
// SMRT parameters that are sometimes used globally
|
|
SHADER_PARAMETER(float, ScreenRayLength)
|
|
SHADER_PARAMETER(float, NormalBias)
|
|
SHADER_PARAMETER(uint32, SMRTAdaptiveRayCount)
|
|
SHADER_PARAMETER(int32, SMRTRayCountLocal)
|
|
SHADER_PARAMETER(int32, SMRTSamplesPerRayLocal)
|
|
SHADER_PARAMETER(float, SMRTExtrapolateMaxSlopeLocal)
|
|
SHADER_PARAMETER(float, SMRTTexelDitherScaleLocal)
|
|
SHADER_PARAMETER(float, SMRTMaxSlopeBiasLocal)
|
|
SHADER_PARAMETER(float, SMRTCotMaxRayAngleFromLight)
|
|
|
|
SHADER_PARAMETER(int32, SMRTRayCountDirectional)
|
|
SHADER_PARAMETER(int32, SMRTSamplesPerRayDirectional)
|
|
SHADER_PARAMETER(float, SMRTExtrapolateMaxSlopeDirectional)
|
|
SHADER_PARAMETER(float, SMRTTexelDitherScaleDirectional)
|
|
SHADER_PARAMETER(float, SMRTRayLengthScale)
|
|
|
|
SHADER_PARAMETER(uint32, SMRTHairRayCount)
|
|
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(ByteAddressBuffer, ProjectionData)
|
|
|
|
SHADER_PARAMETER_SAMPLER(SamplerState, PageTableSampler)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, PageTable)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, PageFlags)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<uint>, PageReceiverMasks)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint4>, AllocatedPageRectBounds)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint4>, UncachedPageRectBounds)
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2DArray<uint>, PhysicalPagePool)
|
|
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<uint>, CachePrimitiveAsDynamic)
|
|
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FVirtualShadowMapPerViewParameters, PerViewData)
|
|
END_GLOBAL_SHADER_PARAMETER_STRUCT()
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FVirtualShadowMapSamplingParameters, )
|
|
// NOTE: These parameters must only be uniform buffers/references! Loose parameters do not get bound
|
|
// in some of the forward passes that use this structure.
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualShadowMapUniformParameters, VirtualShadowMap)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
FMatrix CalcTranslatedWorldToShadowUVMatrix(const FMatrix& TranslatedWorldToShadowView, const FMatrix& ViewToClip);
|
|
FMatrix CalcTranslatedWorldToShadowUVNormalMatrix(const FMatrix& TranslatedWorldToShadowView, const FMatrix& ViewToClip);
|
|
|
|
struct FVirtualShadowMapVisualizeLightSearch
|
|
{
|
|
public:
|
|
FVirtualShadowMapVisualizeLightSearch()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
FoundKey.Packed = 0;
|
|
FoundProxy = nullptr;
|
|
FoundVirtualShadowMapId = INDEX_NONE;
|
|
}
|
|
|
|
void CheckLight(const FLightSceneProxy* CheckProxy, int CheckVirtualShadowMapId);
|
|
void ChooseLight();
|
|
|
|
bool IsValid() const { return FoundProxy != nullptr; }
|
|
|
|
int GetVirtualShadowMapId() const { return FoundVirtualShadowMapId; }
|
|
const FLightSceneProxy* GetProxy() const { return FoundProxy; }
|
|
const FString GetLightName() const;
|
|
|
|
private:
|
|
union SortKey
|
|
{
|
|
struct
|
|
{
|
|
// NOTE: Lowest to highest priority
|
|
uint32 bSelected : 1; // In editor
|
|
uint32 bPartialNameMatch : 1;
|
|
uint32 bExactNameMatch : 1;
|
|
} Fields;
|
|
uint32 Packed;
|
|
};
|
|
|
|
SortKey FoundKey;
|
|
const FLightSceneProxy* FoundProxy = nullptr;
|
|
int FoundVirtualShadowMapId = INDEX_NONE;
|
|
};
|
|
|
|
enum class EVSMVisualizationPostPass
|
|
{
|
|
PreEditorPrimitives,
|
|
PostEditorPrimitives
|
|
};
|
|
|
|
class FVirtualShadowMapArray
|
|
{
|
|
public:
|
|
FVirtualShadowMapArray(FScene& InScene);
|
|
~FVirtualShadowMapArray();
|
|
|
|
void Initialize(
|
|
FRDGBuilder& GraphBuilder,
|
|
FVirtualShadowMapArrayCacheManager* InCacheManager,
|
|
bool bInEnabled,
|
|
const FEngineShowFlags& EngineShowFlags);
|
|
|
|
// Returns true if virtual shadow maps are enabled
|
|
bool IsEnabled() const
|
|
{
|
|
return bEnabled;
|
|
}
|
|
|
|
// Returns the first in a continuously allocated range of new VirtualShadowMapIds
|
|
int32 Allocate(bool bSinglePageShadowMap, int32 Count);
|
|
|
|
// TODO: Can probably make this 1:1 with allocate directly
|
|
void UpdateNextData(int32 PrevVirtualShadowMapId, int32 CurrentVirtualShadowMapId, FInt32Point PageOffset = FInt32Point(0, 0));
|
|
|
|
static bool IsSinglePage(int VirtualShadowMapId)
|
|
{
|
|
return (VirtualShadowMapId < VSM_MAX_SINGLE_PAGE_SHADOW_MAPS);
|
|
}
|
|
|
|
int32 GetNumShadowMapSlots() const
|
|
{
|
|
return NumShadowMapSlots;
|
|
}
|
|
|
|
int32 GetNumFullShadowMaps() const
|
|
{
|
|
return FMath::Max(GetNumShadowMapSlots() - int32(VSM_MAX_SINGLE_PAGE_SHADOW_MAPS), 0);
|
|
}
|
|
|
|
int32 GetNumSinglePageShadowMaps() const
|
|
{
|
|
return NumSinglePageShadowMaps;
|
|
}
|
|
|
|
/**
|
|
* Return the total of allocated SMs, both full and single-page SMs
|
|
*/
|
|
int32 GetNumShadowMaps() const
|
|
{
|
|
// If not initialized ShadowMaps is empty, but we want it to return at most 0 anyway
|
|
return GetNumFullShadowMaps() + GetNumSinglePageShadowMaps();
|
|
}
|
|
|
|
// Raw size of the physical pool, including both static and dynamic pages (if enabled)
|
|
FIntPoint GetPhysicalPoolSize() const;
|
|
// Size of HZB (level 0)
|
|
FIntPoint GetHZBPhysicalPoolSize() const;
|
|
|
|
// Maximum number of physical pages to allocate. This value is NOT doubled when static caching is
|
|
// enabled as we always allocate both as pairs (offset in the page pool).
|
|
uint32 GetMaxPhysicalPages() const { return UniformParameters.MaxPhysicalPages; }
|
|
// Total physical page count that includes separate static pages
|
|
uint32 GetTotalAllocatedPhysicalPages() const;
|
|
|
|
EPixelFormat GetPackedShadowMaskFormat() const;
|
|
|
|
static void SetShaderDefines(FShaderCompilerEnvironment& OutEnvironment);
|
|
|
|
void UpdatePhysicalPageAddresses(FRDGBuilder& GraphBuilder);
|
|
|
|
void BuildPageAllocations(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FMinimalSceneTextures& SceneTextures,
|
|
const TConstArrayView<FViewInfo> &Views,
|
|
const FSceneRenderer& SceneRenderer,
|
|
const TConstArrayView<FVisibleLightInfo>& VisibleLightInfos,
|
|
const FSingleLayerWaterPrePassResult* SingleLayerWaterPrePassResult,
|
|
const FFrontLayerTranslucencyData& FrontLayerTranslucencyData,
|
|
const Froxel::FRenderer& FroxelRenderer,
|
|
bool bAnyLocalLightsWithVSMs);
|
|
|
|
bool IsAllocated() const
|
|
{
|
|
return PhysicalPagePoolRDG != nullptr && PageTableRDG != nullptr;
|
|
}
|
|
|
|
bool ShouldCacheStaticSeparately() const
|
|
{
|
|
return UniformParameters.StaticCachedArrayIndex > 0;
|
|
}
|
|
|
|
bool HasSeparateDynamicHZB() const
|
|
{
|
|
return UniformParameters.StaticHZBArrayIndex > 0;
|
|
}
|
|
|
|
void CreateMipViews(TArray<Nanite::FPackedView, SceneRenderingAllocator>& Views) const;
|
|
|
|
/**
|
|
* Draw Nanite geometry into the VSMs.
|
|
*/
|
|
void RenderVirtualShadowMapsNanite(
|
|
FRDGBuilder& GraphBuilder,
|
|
FSceneRenderer& SceneRenderer,
|
|
bool bUpdateNaniteStreaming,
|
|
const FNaniteVisibilityQuery* VisibilityQuery,
|
|
TConstArrayView<FNaniteVirtualShadowMapRenderPass> VirtualShadowMapPasses);
|
|
|
|
/**
|
|
* Draw Non-Nanite geometry into the VSMs.
|
|
*/
|
|
void RenderVirtualShadowMapsNonNanite(FRDGBuilder& GraphBuilder, FSceneUniformBuffer& SceneUniformBuffer, const TArray<FProjectedShadowInfo*, SceneRenderingAllocator>& VirtualSmMeshCommandPasses, TArrayView<FViewInfo> Views);
|
|
|
|
void PostRender(FRDGBuilder& GraphBuilder);
|
|
|
|
void RenderDebugInfo(FRDGBuilder& GraphBuilder, TArrayView<FViewInfo> Views);
|
|
|
|
bool ShouldGenerateStats() const;
|
|
bool IsCsvLogEnabled() const;
|
|
|
|
void LogStats(FRDGBuilder& GraphBuilder, const FViewInfo& View);
|
|
|
|
// Get shader parameters necessary to sample virtual shadow maps
|
|
// It is safe to bind this buffer even if VSMs are disabled, but the sampling should be branched around in the shader.
|
|
// This data becomes valid after the shadow depths pass if VSMs are enabled
|
|
FVirtualShadowMapSamplingParameters GetSamplingParameters(FRDGBuilder& GraphBuilder, int32 ViewIndex) const;
|
|
TRDGUniformBufferRef<FVirtualShadowMapUniformParameters> GetUniformBuffer(int32 ViewIndex) const
|
|
{
|
|
if (CachedUniformBuffers.IsEmpty())
|
|
{
|
|
return TRDGUniformBufferRef<FVirtualShadowMapUniformParameters>();
|
|
}
|
|
|
|
// If the view index is out of range, then it means VSM has not been set up yet, this is not a great time to access the UB but is actully done in skyatmosphere rendering so we need to return a safe default.
|
|
return CachedUniformBuffers[FMath::Min(ViewIndex, CachedUniformBuffers.Num() - 1)];
|
|
}
|
|
|
|
bool HasAnyShadowData() const { return PhysicalPagePoolRDG != nullptr; }
|
|
|
|
bool ShouldCullBackfacingPixels() const { return bCullBackfacingPixels; }
|
|
|
|
void UpdateHZB(FRDGBuilder& GraphBuilder);
|
|
|
|
// Add render views, and mark shadow maps as rendered for a given clipmap or set of VSMs
|
|
void AddRenderViews(
|
|
const FProjectedShadowInfo* ProjectedShadowInfo,
|
|
TConstArrayView<FViewInfo> Views,
|
|
float LODScaleFactor,
|
|
bool bSetHzbParams,
|
|
bool bUpdateHZBMetaData,
|
|
TArray<Nanite::FPackedView, SceneRenderingAllocator>& OutVirtualShadowViews) const;
|
|
|
|
// Add visualization composite pass, if enabled
|
|
FScreenPassTexture AddVisualizePass(FRDGBuilder& GraphBuilder, const FViewInfo& View, int32 ViewIndex, EVSMVisualizationPostPass Pass, FScreenPassTexture& SceneColor, FScreenPassRenderTarget& Output);
|
|
|
|
//
|
|
bool UseHzbOcclusion() const { return bUseHzbOcclusion; }
|
|
|
|
/**
|
|
* Helper function to add clamping when interpolating the LOD resolution biases to ensure the bias for moving lights can never be lower than the one for not.
|
|
* This could occur fairly easily since it is possible to both set the values through console as well as scalability.
|
|
*/
|
|
static float InterpolateResolutionBias(float BiasNonMoving, float BiasMoving, float LightMobilityFactor);
|
|
|
|
// We keep a reference to the cache manager that was used to initialize this frame as it owns some of the buffers
|
|
FVirtualShadowMapArrayCacheManager* CacheManager = nullptr;
|
|
|
|
FVirtualShadowMapUniformParameters UniformParameters;
|
|
TArray<FVirtualShadowMapPerViewParameters> PerViewParameters;
|
|
|
|
// Physical page pool shadow data and associated HZB and metadata
|
|
// NOTE: The underlying textures are owned by FVirtualShadowMapCacheManager.
|
|
// We just import and maintain a copy of the RDG reference for this frame here.
|
|
FRDGTextureRef PhysicalPagePoolRDG = nullptr;
|
|
TRefCountPtr<IPooledRenderTarget> HZBPhysicalArray = nullptr;
|
|
FRDGTextureRef HZBPhysicalArrayRDG = nullptr;
|
|
FRDGBufferRef PhysicalPageMetaDataRDG = nullptr;
|
|
|
|
// Buffer that serves as the page table for all virtual shadow maps
|
|
FRDGTextureRef PageTableRDG = nullptr;
|
|
// Buffer that holds page requests during marking/page management
|
|
// Later it gets potentially reused to mark invalidations (see VirtualShadowMapArrayCacheManager)
|
|
FRDGTextureRef PageRequestFlagsRDG = nullptr;
|
|
// Buffer that stores flags (uints) marking each page that needs to be rendered and cache status, for all virtual shadow maps.
|
|
// Flag values defined in PageAccessCommon.ush
|
|
FRDGTextureRef PageFlagsRDG = nullptr;
|
|
|
|
// Per-page receiver mask 8x8 bits (stored as 2x2 x 4x4 bits - in 32-bits for now because of atomics, later in true 16-bit words hopefully)
|
|
FRDGTextureRef PageReceiverMasksRDG = nullptr;
|
|
|
|
// Buffer that receives stats from Nanite about the geometry that was rendered into each VSM
|
|
FRDGBufferRef NanitePerformanceFeedbackRDG = nullptr;
|
|
|
|
// Buffer that stores data related to past and current VSM load and performance
|
|
FRDGBufferRef ThrottleBufferRDG = nullptr;
|
|
bool bThrottlingEnabled = false;
|
|
|
|
// List(s) of physical pages used during allocation/updates
|
|
// These can be saved frame to frame to allow keeping an LRU-sorted order for cached pages
|
|
FRDGBufferRef PhysicalPageListsRDG = nullptr;
|
|
|
|
// Allocation info for each page.
|
|
FRDGBufferRef CachedPageInfosRDG = nullptr;
|
|
|
|
// uint4 buffer with one rect for each mip level in all SMs, calculated to bound committed pages
|
|
// Used to clip the rect size of clusters during culling.
|
|
FRDGBufferRef UncachedPageRectBoundsRDG = nullptr; // For rendering; only includes uncached pages
|
|
FRDGBufferRef AllocatedPageRectBoundsRDG = nullptr; // For invalidation; includes all mapped/cached pages
|
|
FRDGBufferRef ProjectionDataRDG = nullptr;
|
|
|
|
FRDGBufferRef DirtyPageFlagsRDG = nullptr; // Dirty flags that are cleared after render passes
|
|
bool bHZBBuiltThisFrame = false;
|
|
|
|
static constexpr uint32 MaxPageAreaDiagnosticSlots = 32;
|
|
|
|
FRDGBufferRef StatsBufferRDG = nullptr;
|
|
FRDGBufferUAVRef StatsBufferUAV = nullptr;
|
|
FRDGBufferRef StatsNaniteBufferRDG = nullptr;
|
|
|
|
// Debug visualization
|
|
TArray<FRDGTextureRef> DebugVisualizationOutput;
|
|
TArray<FVirtualShadowMapVisualizeLightSearch> VisualizeLight;
|
|
bool bEnableVisualization = false;
|
|
bool bEnableNaniteVisualization = false;
|
|
|
|
private:
|
|
void UpdateVisualizeLight(
|
|
const TConstArrayView<FViewInfo> &Views,
|
|
const TConstArrayView<FVisibleLightInfo>& VisibleLightInfos);
|
|
|
|
void AppendPhysicalPageList(FRDGBuilder& GraphBuilder, bool bEmptyToAvailable);
|
|
|
|
void AddRenderViewsLocal(
|
|
const FProjectedShadowInfo* ProjectedShadowInfo,
|
|
TConstArrayView<FViewInfo> Views,
|
|
float LODScaleFactor,
|
|
bool bSetHzbParams,
|
|
bool bUpdateHZBMetaData,
|
|
TArray<Nanite::FPackedView, SceneRenderingAllocator>& OutVirtualShadowViews) const;
|
|
|
|
void AddRenderViewsClipmap(
|
|
const TSharedPtr<FVirtualShadowMapClipmap>& Clipmap,
|
|
const FViewInfo* CullingView,
|
|
float LODScaleFactor,
|
|
bool bSetHzbParams,
|
|
bool bUpdateHZBMetaData,
|
|
TArray<Nanite::FPackedView,
|
|
SceneRenderingAllocator>& OutVirtualShadowViews) const;
|
|
|
|
TRDGUniformBufferRef<FVirtualShadowMapUniformParameters> GetUncachedUniformBuffer(FRDGBuilder& GraphBuilder) const;
|
|
void UpdateCachedUniformBuffers(FRDGBuilder& GraphBuilder);
|
|
|
|
// Track mapping of previous VSM data -> current frame VSM data
|
|
// This is primarily an indirection that allows us to reallocate/repack VirtualShadowMapIds each frame
|
|
TArray<FNextVirtualShadowMapData, SceneRenderingAllocator> NextData;
|
|
|
|
int32 NumShadowMapSlots = 0;
|
|
int32 NumSinglePageShadowMaps = 0;
|
|
|
|
// Gets created in dummy form at initialization time, then updated after VSM data is computed
|
|
TArray<TRDGUniformBufferRef<FVirtualShadowMapUniformParameters>> CachedUniformBuffers;
|
|
|
|
FScene &Scene;
|
|
//
|
|
bool bUseHzbOcclusion = true;
|
|
|
|
bool bInitialized = false;
|
|
|
|
// Are virtual shadow maps enabled? We store this at the start of the frame to centralize the logic.
|
|
bool bEnabled = false;
|
|
|
|
// Is backface culling of pixels enabled? We store this here to keep it consistent between projection and generation
|
|
bool bCullBackfacingPixels = false;
|
|
|
|
FRDGTextureRef PageTableDummyRDG = nullptr;
|
|
};
|