You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb none #preflight https://horde.devtools.epicgames.com/job/6374f970b6636838280f3278 #fyi charles.derousiers [CL 23155230 by Sebastien Hillaire in ue5-main branch]
531 lines
20 KiB
Plaintext
531 lines
20 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "/Engine/Private/Common.ush"
|
|
|
|
#define STRATA_INLINE_SHADING 0
|
|
#define STRATA_SSS_MATERIAL_OVERRIDE 0
|
|
#include "/Engine/Private/Strata/Strata.ush"
|
|
#include "StrataTile.ush"
|
|
|
|
#define GROUP_THREAD_COUNT (STRATA_TILE_SIZE * STRATA_TILE_SIZE)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_TILE_CATEGORIZATION
|
|
int bRectPrimitive;
|
|
int2 ViewResolution;
|
|
uint MaxBytesPerPixel;
|
|
int FirstSliceStoringStrataSSSData;
|
|
Texture2D<uint2> TopLayerTexture;
|
|
#if PERMUTATION_CMASK
|
|
Texture2D<uint> TopLayerCmaskTexture;
|
|
#endif
|
|
RWTexture2DArray<uint> MaterialTextureArrayUAV;
|
|
|
|
// Indirect draw data buffer for all tile types
|
|
RWBuffer<uint> TileDrawIndirectDataBuffer;
|
|
|
|
RWBuffer<uint> SimpleTileListDataBuffer;
|
|
RWBuffer<uint> SingleTileListDataBuffer;
|
|
RWBuffer<uint> ComplexTileListDataBuffer;
|
|
|
|
#if PERMUTATION_DECAL
|
|
RWBuffer<uint> DecalSimpleTileListDataBuffer;
|
|
RWBuffer<uint> DecalSingleTileListDataBuffer;
|
|
RWBuffer<uint> DecalComplexTileListDataBuffer;
|
|
|
|
Texture2D<float4> DBufferATexture;
|
|
Texture2D<float4> DBufferBTexture;
|
|
Texture2D<float4> DBufferCTexture;
|
|
Texture2D<uint> DBufferRenderMask;
|
|
|
|
SamplerState DBufferATextureSampler;
|
|
SamplerState DBufferBTextureSampler;
|
|
SamplerState DBufferCTextureSampler;
|
|
|
|
// @param BufferUV - UV space in the DBuffer textures
|
|
uint GetDBufferTargetMask(uint2 PixelPos)
|
|
{
|
|
#if PLATFORM_SUPPORTS_RENDERTARGET_WRITE_MASK
|
|
return DecodeRTWriteMask(PixelPos, DBufferRenderMask, 3);
|
|
#elif PLATFORM_SUPPORTS_PER_PIXEL_DBUFFER_MASK
|
|
uint Mask = DBufferRenderMask.Load(uint3(PixelPos, 0));
|
|
return Mask > 0 ? 0x07 : 0x00;
|
|
#else
|
|
// For debug purpose:
|
|
// return
|
|
// (DBufferATexture.Load(uint3(PixelPos, 0)).a < 1.f ? 0x1 : 0x0) |
|
|
// (DBufferBTexture.Load(uint3(PixelPos, 0)).a < 1.f ? 0x2 : 0x0) |
|
|
// (DBufferCTexture.Load(uint3(PixelPos, 0)).a < 1.f ? 0x3 : 0x0) ;
|
|
return 0x07;
|
|
#endif
|
|
}
|
|
|
|
#endif // PERMUTATION_DECAL
|
|
|
|
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
RWBuffer<uint> OpaqueRoughRefractionTileListDataBuffer;
|
|
RWBuffer<uint> OpaqueRoughRefractionSSSWithoutTileListDataBuffer;
|
|
Texture2D<float3> OpaqueRoughRefractionTexture;
|
|
#endif // STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
|
|
#if !PERMUTATION_WAVE_OPS
|
|
groupshared uint s_TileFlags[GROUP_THREAD_COUNT];
|
|
#endif
|
|
|
|
#if PERMUTATION_WAVE_OPS && COMPILER_SUPPORTS_WAVE_SIZE
|
|
WAVESIZE(64) // PERMUTATION_WAVE_OPS is true only when wave>=64 are available
|
|
#endif
|
|
[numthreads(STRATA_TILE_SIZE, STRATA_TILE_SIZE, 1)]
|
|
void TileMainCS(uint2 DispatchThreadId : SV_DispatchThreadID, uint LinearIndex : SV_GroupIndex, uint3 GroupId : SV_GroupID)
|
|
{
|
|
// Init primitive index
|
|
if (DispatchThreadId.x < STRATA_TILE_TYPE_COUNT && DispatchThreadId.y == 0)
|
|
{
|
|
const uint TileType = DispatchThreadId.x;
|
|
const uint IndexCountPerInstance = bRectPrimitive > 0 ? 4 : 6;
|
|
TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(TileType) + 0] = IndexCountPerInstance;
|
|
}
|
|
|
|
const uint2 PixelCoord = DispatchThreadId.xy + View.ViewRectMin.xy;
|
|
const bool bIsValid = all(DispatchThreadId.xy < uint2(View.ViewSizeAndInvSize.xy));
|
|
|
|
// If CMask data are available, we use it as a coarse evaluation to know if a tile contains any data.
|
|
// * If the tile is entirely empty: we clear the header & SSS data
|
|
// * If the data contains any data: we do fine grain checking, and clear header & SSS data only for needed pixels. The top layer data texture is used
|
|
// to know if a pixel is valid or not (since the material header is not cleared when the Cmask permutation is used).
|
|
|
|
#if PERMUTATION_CMASK
|
|
// Coarse test for clearing header (& SSS data) based on CMask data
|
|
const uint CMask = TopLayerCmaskTexture.Load(uint3(GroupId.xy, 0));
|
|
BRANCH
|
|
if (CMask == 0x0)
|
|
{
|
|
MaterialTextureArrayUAV[uint3(PixelCoord, 0)] = 0u;
|
|
StrataStoreSubsurfaceHeader(MaterialTextureArrayUAV, FirstSliceStoringStrataSSSData, PixelCoord, 0u); // This is a good clear for FStrataSubsurfaceHeader, and we only need to clear the header.
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
|
|
// Pixels outside of the view area are considered simple to enable screen borders to receive the simple permutation when not aligned to shader group size.
|
|
bool bContainsComplexMaterial = false;
|
|
bool bContainsSimpleMaterial = false;
|
|
bool bContainsSingleMaterial = false;
|
|
bool bContainsStrataMaterial = false;
|
|
bool bContainsDecals = false;
|
|
bool bContainsOpaqueRoughRefraction = false;
|
|
bool bContainsScreenSpaceSubsurfaceScattering = false;
|
|
|
|
FStrataOpaqueRoughRefractionData OpaqueRoughRefractionData = (FStrataOpaqueRoughRefractionData)0;
|
|
if (bIsValid)
|
|
{
|
|
FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(PixelCoord, uint2(View.BufferSizeAndInvSize.xy), MaxBytesPerPixel);
|
|
|
|
// Load mini header.
|
|
const uint PackedHeader = MaterialTextureArrayUAV[uint3(PixelCoord, 0)];
|
|
FStrataPixelHeader StrataPixelHeader = UnpackStrataHeaderIn(PackedHeader, StrataAddressing, TopLayerTexture);
|
|
|
|
const bool bIsSimple = IsSimpleMaterial(StrataPixelHeader) || StrataPixelHeader.BSDFCount == 0; // BSDFCount == 0 ensures that non-strata pixel, like sky pixels, won't make a simple tile flagged as complex
|
|
const bool bIsSingle = !IsSimpleMaterial(StrataPixelHeader) && IsSingleMaterial(StrataPixelHeader);
|
|
bContainsStrataMaterial = StrataPixelHeader.BSDFCount > 0;
|
|
bContainsSimpleMaterial = bIsSimple;
|
|
bContainsSingleMaterial = bIsSingle;
|
|
bContainsComplexMaterial = !bIsSingle && !bIsSimple;
|
|
bContainsScreenSpaceSubsurfaceScattering = HasSubsurface(StrataPixelHeader);
|
|
|
|
#if PERMUTATION_DECAL
|
|
const uint DBufferResponseMask = SceneStencilTexture.Load(uint3(PixelCoord, 0)) STENCIL_COMPONENT_SWIZZLE;
|
|
const uint DBufferTargetMask = GetDBufferTargetMask(PixelCoord);
|
|
bContainsDecals = DBufferResponseMask != 0 && DBufferTargetMask != 0;
|
|
#endif
|
|
|
|
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
OpaqueRoughRefractionData = StrataUnpackOpaqueRoughRefractionData(OpaqueRoughRefractionTexture[PixelCoord]);
|
|
bContainsOpaqueRoughRefraction = OpaqueRoughRefractionData.OpaqueRoughRefractionEnabled > 0.0f;
|
|
#endif
|
|
|
|
// Output/Patch SSS data for legacy encoding (this allows to save ALU & bandwidth during the base pass0
|
|
uint OptimisedLegacyMode = ((PackedHeader >> (HEADER_SINGLEENCODING_BIT_COUNT)) & HEADER_SINGLE_OPTLEGACYMODE_BIT_MASK);
|
|
const bool bIsLegacyWrap = OptimisedLegacyMode == SINGLE_OPTLEGACYMODE_SSSWRAP;
|
|
const bool bIsLegacySSSProfile = OptimisedLegacyMode == SINGLE_OPTLEGACYMODE_SSSPROFILE;
|
|
if (bIsSingle && (bIsLegacyWrap || bIsLegacySSSProfile))
|
|
{
|
|
bContainsScreenSpaceSubsurfaceScattering = true;
|
|
if (bIsLegacyWrap)
|
|
{
|
|
const uint PackedSSSWOpacity7bits = (PackedHeader >> (HEADER_SINGLEENCODING_BIT_COUNT + HEADER_SINGLE_OPTLEGACYMODE_BIT_COUNT)) & 0x7F;
|
|
FStrataSubsurfaceHeader SSSHeader = (FStrataSubsurfaceHeader)0;
|
|
StrataSubSurfaceHeaderSetSSSType(SSSHeader, SSS_TYPE_WRAP);
|
|
StrataSubSurfaceHeaderSetWrapOpacity(SSSHeader, UnpackR7(PackedSSSWOpacity7bits));
|
|
StrataStoreSubsurfaceHeader(MaterialTextureArrayUAV, FirstSliceStoringStrataSSSData, PixelCoord, SSSHeader.Bytes);
|
|
}
|
|
else if (bIsLegacySSSProfile)
|
|
{
|
|
const uint Data1 = MaterialTextureArrayUAV[uint3(PixelCoord, 1)];
|
|
const uint Data2 = MaterialTextureArrayUAV[uint3(PixelCoord, 2)];
|
|
float RadiusScale = UnpackR8(Data1 >> 24);
|
|
float ProfileId = UnpackR8(Data2 >> 24);
|
|
|
|
const uint PackedDiffuse20Bits = (Data1 & 0xFFFFF);
|
|
const float3 BaseColor = UnpackR7G7B6Gamma2(PackedDiffuse20Bits);
|
|
|
|
FStrataSubsurfaceHeader SSSHeader = (FStrataSubsurfaceHeader)0;
|
|
StrataSubSurfaceHeaderSetSSSType(SSSHeader, SSS_TYPE_DIFFUSION_PROFILE);
|
|
StrataSubSurfaceHeaderSetProfile(SSSHeader, RadiusScale, StrataSubsurfaceProfileIdTo8bits(ProfileId));
|
|
|
|
FStrataSubsurfaceExtras SSSExtras = (FStrataSubsurfaceExtras)0;
|
|
StrataSubsurfaceExtrasSetBaseColor(SSSExtras, BaseColor);
|
|
|
|
StrataStoreSubsurfaceHeader(MaterialTextureArrayUAV, FirstSliceStoringStrataSSSData, PixelCoord, SSSHeader.Bytes);
|
|
StrataStoreSubsurfaceExtras(MaterialTextureArrayUAV, FirstSliceStoringStrataSSSData, PixelCoord, SSSExtras.Bytes);
|
|
}
|
|
}
|
|
|
|
// Fine grain test for clearing based on CMask data
|
|
#if PERMUTATION_CMASK
|
|
// Fine grain check if clear is needed
|
|
bool bClearHeader = false;
|
|
BRANCH
|
|
if (CMask > 0u && CMask < 0xF)
|
|
{
|
|
bClearHeader = TopLayerTexture.Load(uint3(PixelCoord,0)) == 0;
|
|
}
|
|
|
|
// Header clear
|
|
BRANCH
|
|
if (bClearHeader)
|
|
{
|
|
MaterialTextureArrayUAV[uint3(PixelCoord, 0)] = 0u;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BRANCH
|
|
if (!bContainsScreenSpaceSubsurfaceScattering)
|
|
{
|
|
// We must fill all the pixel which does not have subsurface scattering by default so that the SSS code is not executed where it should not.
|
|
StrataStoreSubsurfaceHeader(MaterialTextureArrayUAV, FirstSliceStoringStrataSSSData, PixelCoord, 0u); // This is a good clear for FStrataSubsurfaceHeader, and we only need to clear the header.
|
|
}
|
|
|
|
#if PERMUTATION_WAVE_OPS
|
|
const bool bTileContainsStrata = WaveActiveAnyTrue(bContainsStrataMaterial);
|
|
const bool bTileContainsSimple = WaveActiveAnyTrue(bContainsSimpleMaterial);
|
|
const bool bTileContainsSingle = WaveActiveAnyTrue(bContainsSingleMaterial);
|
|
const bool bTileContainsComplex = WaveActiveAnyTrue(bContainsComplexMaterial);
|
|
const bool bTileContainsOpaqueRoughRefraction = WaveActiveAnyTrue(bContainsOpaqueRoughRefraction);
|
|
const bool bTileContainsScreenSpaceSubsurfaceScattering = WaveActiveAnyTrue(bContainsScreenSpaceSubsurfaceScattering);
|
|
const bool bTileContainsDecals = WaveActiveAnyTrue(bContainsDecals);
|
|
#else // PERMUTATION_WAVE_OPS
|
|
|
|
s_TileFlags[LinearIndex] =
|
|
(bContainsStrataMaterial ? 0x1u : 0u)
|
|
| (bContainsSimpleMaterial ? 0x2u : 0u)
|
|
| (bContainsSingleMaterial ? 0x4u : 0u)
|
|
| (bContainsComplexMaterial ? 0x8u : 0u)
|
|
| (bContainsOpaqueRoughRefraction ? 0x10u : 0u)
|
|
| (bContainsScreenSpaceSubsurfaceScattering ? 0x20u : 0u)
|
|
| (bContainsScreenSpaceSubsurfaceScattering ? 0x20u : 0u)
|
|
| (bContainsDecals ? 0x40u : 0u);
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 32)
|
|
{
|
|
s_TileFlags[LinearIndex] = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 32];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 16)
|
|
{
|
|
s_TileFlags[LinearIndex] = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 16];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (LinearIndex < 8)
|
|
{
|
|
s_TileFlags[LinearIndex] = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 8];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 4)
|
|
{
|
|
s_TileFlags[LinearIndex] = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 4];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 2)
|
|
{
|
|
s_TileFlags[LinearIndex] = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 2];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
const uint FinalTileFlags = s_TileFlags[LinearIndex] | s_TileFlags[LinearIndex + 1];
|
|
|
|
const bool bTileContainsStrata = (FinalTileFlags & 0x1u) > 0;
|
|
const bool bTileContainsSimple = (FinalTileFlags & 0x2u) > 0;
|
|
const bool bTileContainsSingle = (FinalTileFlags & 0x4u) > 0;
|
|
const bool bTileContainsComplex = (FinalTileFlags & 0x8u) > 0;
|
|
const bool bTileContainsOpaqueRoughRefraction = (FinalTileFlags & 0x10u) > 0;
|
|
const bool bTileContainsScreenSpaceSubsurfaceScattering = (FinalTileFlags & 0x20u) > 0;
|
|
const bool bTileContainsDecals = (FinalTileFlags & 0x40u) > 0;
|
|
#endif // PERMUTATION_WAVE_OPS
|
|
|
|
if (LinearIndex < 1 && bTileContainsStrata)
|
|
{
|
|
uint EncodedTile = StrataPackTile(GroupId.xy);
|
|
|
|
if (bTileContainsComplex)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_COMPLEX) + 1], 1, WriteToIndex);
|
|
ComplexTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
else if (bTileContainsSingle)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_SINGLE) + 1], 1, WriteToIndex);
|
|
SingleTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
else // (bTileContainsSimple)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_SIMPLE) + 1], 1, WriteToIndex);
|
|
SimpleTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
|
|
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
|
|
if (bTileContainsOpaqueRoughRefraction)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_ROUGH_REFRACT) + 1], 1, WriteToIndex);
|
|
OpaqueRoughRefractionTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
if(bTileContainsScreenSpaceSubsurfaceScattering && !bTileContainsOpaqueRoughRefraction)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_ROUGH_REFRACT_SSS_WITHOUT) + 1], 1, WriteToIndex);
|
|
OpaqueRoughRefractionSSSWithoutTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
#endif
|
|
|
|
#if PERMUTATION_DECAL
|
|
if (bTileContainsDecals)
|
|
{
|
|
if (bTileContainsComplex)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_DECAL_COMPLEX) + 1], 1, WriteToIndex);
|
|
DecalComplexTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
else if (bTileContainsSingle)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_DECAL_SINGLE) + 1], 1, WriteToIndex);
|
|
DecalSingleTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
else // (bTileContainsSimple)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(STRATA_TILE_TYPE_DECAL_SIMPLE) + 1], 1, WriteToIndex);
|
|
DecalSimpleTileListDataBuffer[WriteToIndex] = EncodedTile;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if PERMUTATION_CMASK
|
|
}
|
|
#endif
|
|
}
|
|
#endif // SHADER_TILE_CATEGORIZATION
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_MATERIAL_TILE_PREPARE_ARGS
|
|
|
|
Buffer<uint> TileDrawIndirectDataBuffer;
|
|
RWBuffer<uint> TileDispatchIndirectDataBuffer;
|
|
|
|
[numthreads(32, 1, 1)]
|
|
void ArgsMainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint TileType = DispatchThreadId.x;
|
|
if (TileType < STRATA_TILE_TYPE_COUNT)
|
|
{
|
|
TileDispatchIndirectDataBuffer[GetStrataTileTypeDispatchIndirectArgOffset_DWord(TileType) + 0] = TileDrawIndirectDataBuffer[GetStrataTileTypeDrawIndirectArgOffset_DWord(TileType) + 1];
|
|
TileDispatchIndirectDataBuffer[GetStrataTileTypeDispatchIndirectArgOffset_DWord(TileType) + 1] = 1;
|
|
TileDispatchIndirectDataBuffer[GetStrataTileTypeDispatchIndirectArgOffset_DWord(TileType) + 2] = 1;
|
|
}
|
|
}
|
|
|
|
#endif // SHADER_MATERIAL_TILE_PREPARE_ARGS
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_BSDF_TILE_PREPARE_ARGS
|
|
|
|
int2 TileCount_Primary;
|
|
int2 TileOffset_Primary;
|
|
|
|
int2 OverflowTileCount;
|
|
int2 OverflowTileOffset;
|
|
|
|
Buffer<uint> TileDrawIndirectDataBuffer;
|
|
RWBuffer<uint> TileDispatchIndirectDataBuffer;
|
|
RWBuffer<uint> TileDispatchPerThreadIndirectDataBuffer;
|
|
|
|
[numthreads(1, 1, 1)]
|
|
void ArgsMainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
if (all(DispatchThreadId == 0))
|
|
{
|
|
const uint TileCount = TileDrawIndirectDataBuffer[0].x;
|
|
const uint DispatchX = min(TileCount, uint(OverflowTileCount.x));
|
|
const uint DispatchY = DivideAndRoundUp(TileCount, OverflowTileCount.x);
|
|
|
|
TileDispatchIndirectDataBuffer[0] = DispatchX;
|
|
TileDispatchIndirectDataBuffer[1] = DispatchY;
|
|
TileDispatchIndirectDataBuffer[2] = 1;
|
|
|
|
TileDispatchPerThreadIndirectDataBuffer[0] = DivideAndRoundUp(DispatchX, STRATA_TILE_SIZE);
|
|
TileDispatchPerThreadIndirectDataBuffer[1] = DivideAndRoundUp(DispatchY, STRATA_TILE_SIZE);
|
|
TileDispatchPerThreadIndirectDataBuffer[2] = 1;
|
|
}
|
|
}
|
|
|
|
#endif // SHADER_BSDF_TILE_PREPARE_ARGS
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_BSDF_TILE
|
|
|
|
int2 ViewResolution;
|
|
uint MaxBytesPerPixel;
|
|
uint TileSizeLog2;
|
|
|
|
int2 TileCount_Primary;
|
|
int2 TileOffset_Primary;
|
|
|
|
int2 OverflowTileCount;
|
|
int2 OverflowTileOffset;
|
|
|
|
Texture2D<uint2> TopLayerTexture;
|
|
Texture2DArray<uint> MaterialTextureArray;
|
|
|
|
Buffer<uint> TileListBuffer;
|
|
|
|
RWTexture2D<uint> RWBSDFTileTexture;
|
|
RWTexture2D<uint> RWBSDFOffsetTexture;
|
|
RWBuffer<uint> RWBSDFTileCountBuffer;
|
|
|
|
#if !PERMUTATION_WAVE_OPS
|
|
groupshared uint s_TileBSDFCount[GROUP_THREAD_COUNT];
|
|
#endif
|
|
|
|
uint2 LinearCoordToTileCoord(uint InLinear)
|
|
{
|
|
return uint2(InLinear % OverflowTileCount.x, InLinear / OverflowTileCount.x) + OverflowTileOffset;
|
|
}
|
|
|
|
#if PERMUTATION_WAVE_OPS && COMPILER_SUPPORTS_WAVE_SIZE
|
|
WAVESIZE(64) // PERMUTATION_WAVE_OPS is true only when wave>=64 are available
|
|
#endif
|
|
[numthreads(STRATA_TILE_SIZE, STRATA_TILE_SIZE, 1)]
|
|
void BSDFTileMainCS(uint2 GroupThreadId : SV_GroupThreadID, uint2 GroupId : SV_GroupID, uint LinearIndex : SV_GroupIndex)
|
|
{
|
|
const uint2 TileCoord = StrataUnpackTile(TileListBuffer[GroupId.x]);
|
|
const uint2 PixelCoord = TileCoord * STRATA_TILE_SIZE + GroupThreadId;
|
|
|
|
uint BSDFCount = 0;
|
|
if (all(PixelCoord < uint2(ViewResolution)))
|
|
{
|
|
FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(PixelCoord, uint2(View.BufferSizeAndInvSize.xy), MaxBytesPerPixel);
|
|
FStrataPixelHeader StrataPixelHeader = UnpackStrataHeaderIn(MaterialTextureArray, StrataAddressing, TopLayerTexture);
|
|
BSDFCount = min(StrataPixelHeader.BSDFCount, STRATA_MAX_BSDF_COUNT_FOR_BDSFOFFSET);
|
|
|
|
if (BSDFCount > 0)
|
|
{
|
|
FStrataBSDFOffset Offsets = (FStrataBSDFOffset)0;
|
|
Offsets.BSDFCount = BSDFCount;
|
|
|
|
UNROLL_N(STRATA_MAX_BSDF_COUNT_FOR_BDSFOFFSET)
|
|
for (uint BSDFIndex = 0; BSDFIndex < BSDFCount; ++BSDFIndex)
|
|
{
|
|
Offsets.BSDFOffsets[BSDFIndex] = StrataAddressing.CurrentIndex;
|
|
UnpackStrataBSDFIn(MaterialTextureArray, StrataAddressing, StrataPixelHeader);
|
|
}
|
|
|
|
RWBSDFOffsetTexture[PixelCoord] = PackBSDFOffset(Offsets);
|
|
}
|
|
}
|
|
|
|
#if PERMUTATION_WAVE_OPS
|
|
|
|
const uint TileBSDFCount = WaveActiveMax(BSDFCount);
|
|
|
|
#else // PERMUTATION_WAVE_OPS
|
|
|
|
s_TileBSDFCount[LinearIndex] = BSDFCount;
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 32)
|
|
{
|
|
s_TileBSDFCount[LinearIndex] = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 32]);
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 16)
|
|
{
|
|
s_TileBSDFCount[LinearIndex] = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 16]);
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (LinearIndex < 8)
|
|
{
|
|
s_TileBSDFCount[LinearIndex] = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 8]);
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 4)
|
|
{
|
|
s_TileBSDFCount[LinearIndex] = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 4]);
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 2)
|
|
{
|
|
s_TileBSDFCount[LinearIndex] = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 2]);
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
const uint TileBSDFCount = max(s_TileBSDFCount[LinearIndex], s_TileBSDFCount[LinearIndex + 1]);
|
|
|
|
#endif // PERMUTATION_WAVE_OPS
|
|
|
|
if (LinearIndex < 1)
|
|
{
|
|
if (TileBSDFCount > 1)
|
|
{
|
|
uint LinearTileCoord = 0;
|
|
InterlockedAdd(RWBSDFTileCountBuffer[0], TileBSDFCount - 1, LinearTileCoord);
|
|
|
|
FStrataBSDFTile Tile;
|
|
Tile.Count = TileBSDFCount;
|
|
Tile.Index = 0;
|
|
|
|
// For first/parent tile, set TileCoord to point towards the first 'overflow' tile
|
|
Tile.TileCoord = LinearCoordToTileCoord(LinearTileCoord);
|
|
RWBSDFTileTexture[TileCoord] = PackBSDFTile(Tile);
|
|
|
|
// For 'overflow' tiles, set TileCoord to point towards the first/parent tile
|
|
Tile.TileCoord = TileCoord;
|
|
for (uint BSDFIndex = 1; BSDFIndex < TileBSDFCount; ++BSDFIndex)
|
|
{
|
|
const uint2 OverflowCoord = LinearCoordToTileCoord(LinearTileCoord + BSDFIndex - 1);
|
|
|
|
Tile.Index = BSDFIndex;
|
|
RWBSDFTileTexture[OverflowCoord] = PackBSDFTile(Tile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RWBSDFTileTexture[GroupId] = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif // SHADER_BSDF_TILE
|