Files
UnrealEngine/Engine/Shaders/Private/VirtualShadowMaps/VirtualShadowMapCompactViews.usf
2025-05-18 13:04:45 +08:00

112 lines
4.0 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
VirtualShadowMapCompactViews.usf:
=============================================================================*/
#include "../Common.ush"
#include "/Engine/Shared/VirtualShadowMapDefinitions.h"
#include "/Engine/Shared/SceneCullingDefinitions.h"
#define NANITE_MULTI_VIEW 1
#include "../Nanite/NaniteDataDecode.ush"
RWStructuredBuffer< FPackedNaniteView > CompactedViewsOut;
RWStructuredBuffer< uint > CompactedViewsAllocationOut;
RWStructuredBuffer< FViewDrawGroup > InOutViewDrawRanges;
uint NumViewRanges;
// Cube map (6 faces) with max mips is the current limiter
// In theory clipmaps could go to higher counts but they are practically limited to 32 currently
// due to the coarse page bitmask and a few other things
#define VSM_MAX_VIEWS_PER_GROUP (VSM_MAX_MIP_LEVELS*6)
groupshared uint OutputViewId[VSM_MAX_VIEWS_PER_GROUP];
groupshared uint OutputViewCount;
groupshared uint OutputViewRangeOffset;
uint PackViewIdMip(uint PrimaryViewId, uint MipLevel)
{
return (PrimaryViewId << 4) | MipLevel;
}
uint2 UnpackViewIdMip(uint Packed)
{
return uint2(Packed >> 4, Packed & 0xF);
}
[numthreads(VSM_MAX_VIEWS_PER_GROUP, 1, 1)]
void CompactViewsVSM_CS(
uint GroupId : SV_GroupID,
uint ThreadId : SV_GroupIndex)
{
// Order-preserving compaction
// Could be a wave ops, but portable wave size assumptions are inconvenient here
// Fast enough to just do this scalar as long a we vectorize the actual copy below
if (ThreadId == 0)
{
const uint ViewGroupIndex = GroupId.x;
uint OutputViewOffset = 0U;
FViewDrawGroup ViewDrawGroup = InOutViewDrawRanges[ViewGroupIndex];
for (uint PrimaryViewId = ViewDrawGroup.FirstView; PrimaryViewId < ViewDrawGroup.FirstView + ViewDrawGroup.NumViews; ++PrimaryViewId)
{
FNaniteView PrimaryNaniteView = GetNaniteView(PrimaryViewId);
for (uint MipLevel = 0; MipLevel < (uint)PrimaryNaniteView.TargetNumMipLevels; MipLevel++)
{
uint4 RectPages = VirtualShadowMap.UncachedPageRectBounds[PrimaryNaniteView.TargetLayerIndex * VSM_MAX_MIP_LEVELS + MipLevel];
if (all(RectPages.zw >= RectPages.xy))
{
OutputViewId[OutputViewOffset] = PackViewIdMip(PrimaryViewId, MipLevel);
OutputViewOffset += 1U;
}
}
}
OutputViewCount = OutputViewOffset;
InterlockedAdd(CompactedViewsAllocationOut[1], OutputViewCount, OutputViewRangeOffset);
{
FViewDrawGroup ViewDrawGroupResult;
ViewDrawGroupResult.FirstView = OutputViewRangeOffset;
ViewDrawGroupResult.NumViews = OutputViewCount;
InOutViewDrawRanges[ViewGroupIndex] = ViewDrawGroupResult;
}
}
GroupMemoryBarrierWithGroupSync();
// Copy/generate any views that survived into their compacted locations
if (ThreadId < OutputViewCount)
{
uint CompactedOutputOffset = OutputViewRangeOffset + ThreadId;
// Load associated primary view
uint2 PrimaryViewIdMipLevel = UnpackViewIdMip(OutputViewId[ThreadId]);
uint PrimaryViewId = PrimaryViewIdMipLevel.x;
uint MipLevel = PrimaryViewIdMipLevel.y;
FPackedNaniteView PrimaryNaniteView = InViews[PrimaryViewId];
// Modify a few fields to make it the appropriate mip view
FPackedNaniteView MipView = PrimaryNaniteView;
MipView.TargetLayerIdX_AndMipLevelY_AndNumMipLevelsZ.y = MipLevel;
uint MipDim = VSM_VIRTUAL_MAX_RESOLUTION_XY >> MipLevel;
MipView.ViewRect = uint4(0, 0, MipDim, MipDim);
MipView.HZBTestViewRect = MipView.ViewRect;
MipView.ViewSizeAndInvSize = float4(MipDim, MipDim, 1.0f / MipDim, 1.0f / MipDim);
float ScaleFactor = 1.0f / float(1U << MipLevel);
MipView.LODScales = ScaleFactor * PrimaryNaniteView.LODScales;
MipView.ClipSpaceScaleOffset.x = PrimaryNaniteView.ClipSpaceScaleOffset.x * ScaleFactor;
MipView.ClipSpaceScaleOffset.y = PrimaryNaniteView.ClipSpaceScaleOffset.y * ScaleFactor;
MipView.ClipSpaceScaleOffset.z = MipView.ClipSpaceScaleOffset.x - 1.0f;
MipView.ClipSpaceScaleOffset.w = -MipView.ClipSpaceScaleOffset.y + 1.0f;
// Write final mip view
CompactedViewsOut[CompactedOutputOffset] = MipView;
}
}