Files
UnrealEngineUWP/Engine/Shaders/Private/LightGridCommon.ush
florin pascu bbd6d91e43 Solve OOB access of FLocalLightData when LinkedListCulling is off.
Add GetMaxLightsPerCell that returns GMaxCulledLightsPerCell when LinkedListCulling is off and NumLocalLightsFinal when it is on
Replace calls of GetNumLocalLights with the GetMaxLightsPerCell where it would cause an OOB if used with LinkedListCulling off

[CL 27022928 by florin pascu in ue5-main branch]
2023-08-11 01:53:21 -04:00

359 lines
12 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightGridCommon.ush
=============================================================================*/
#pragma once
#include "LightData.ush"
#if MOBILE_MULTI_VIEW
#define ForwardLightDataISR MobileBasePass.ForwardMMV
#elif INSTANCED_STEREO
#if MATERIALBLENDING_ANY_TRANSLUCENT
#define ForwardLightDataISR TranslucentBasePass.Shared.ForwardISR
#else
#define ForwardLightDataISR OpaqueBasePass.Shared.ForwardISR
#endif
#endif
// If this is changed, the LightGridUses16BitBuffers function from LightGridInjection.cpp should also be updated.
#define LIGHT_GRID_USES_16BIT_BUFFERS (PLATFORM_SUPPORTS_BUFFER_LOAD_TYPE_CONVERSION && !SHADING_PATH_MOBILE)
// ForwardLightData.CulledLightDataGrid could be 32bit StructuredBuffer or 16bit Buffer, make sure to access it from this function
uint GetCulledLightDataGrid(uint GridIndex)
{
#if LIGHT_GRID_USES_16BIT_BUFFERS
return ForwardLightData.CulledLightDataGrid16Bit[GridIndex];
#else
return ForwardLightData.CulledLightDataGrid32Bit[GridIndex];
#endif
}
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
uint GetCulledLightDataGridISR(uint GridIndex)
{
#if LIGHT_GRID_USES_16BIT_BUFFERS
return ForwardLightDataISR.CulledLightDataGrid16Bit[GridIndex];
#else
return ForwardLightDataISR.CulledLightDataGrid32Bit[GridIndex];
#endif
}
#endif
struct FLightGridData
{
uint LightGridPixelSizeShift;
float3 LightGridZParams;
int3 CulledGridSize;
};
FLightGridData GetLightGridData(uint EyeIndex)
{
FLightGridData Result;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
BRANCH
if (EyeIndex == 0)
{
#endif
Result.LightGridPixelSizeShift = ForwardLightData.LightGridPixelSizeShift;
Result.LightGridZParams = ForwardLightData.LightGridZParams;
Result.CulledGridSize = ForwardLightData.CulledGridSize;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
}
else
{
Result.LightGridPixelSizeShift = ForwardLightDataISR.LightGridPixelSizeShift;
Result.LightGridZParams = ForwardLightDataISR.LightGridZParams;
Result.CulledGridSize = ForwardLightDataISR.CulledGridSize;
}
#endif
return Result;
}
uint3 ComputeLightGridCellCoordinate(uint2 PixelPos, float SceneDepth, uint EyeIndex)
{
const FLightGridData GridData = GetLightGridData(EyeIndex);
uint ZSlice = (uint)(max(0, log2(SceneDepth * GridData.LightGridZParams.x + GridData.LightGridZParams.y) * GridData.LightGridZParams.z));
ZSlice = min(ZSlice, (uint)(GridData.CulledGridSize.z - 1));
return uint3(PixelPos >> GridData.LightGridPixelSizeShift, ZSlice);
}
uint ComputeLightGridCellIndex(uint3 GridCoordinate, uint EyeIndex)
{
const FLightGridData GridData = GetLightGridData(EyeIndex);
return (GridCoordinate.z * GridData.CulledGridSize.y + GridCoordinate.y) * GridData.CulledGridSize.x + GridCoordinate.x;
}
uint ComputeLightGridCellIndex(uint2 PixelPos, float SceneDepth, uint EyeIndex)
{
return ComputeLightGridCellIndex(ComputeLightGridCellCoordinate(PixelPos, SceneDepth, EyeIndex), EyeIndex);
}
uint ComputeLightGridCellIndex(uint2 PixelPos, float SceneDepth)
{
return ComputeLightGridCellIndex(PixelPos, SceneDepth, 0);
}
#ifndef NUM_CULLED_LIGHTS_GRID_STRIDE
#define NUM_CULLED_LIGHTS_GRID_STRIDE 0
#endif
#ifndef LOCAL_LIGHT_DATA_STRIDE
#define LOCAL_LIGHT_DATA_STRIDE 0
#endif
uint GetNumLocalLights(uint EyeIndex)
{
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
return (EyeIndex == 0) ? ForwardLightData.NumLocalLights : ForwardLightDataISR.NumLocalLights;
#else
return ForwardLightData.NumLocalLights;
#endif
}
uint GetMaxLightsPerCell(uint EyeIndex)
{
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
return (EyeIndex == 0) ? ForwardLightData.MaxCulledLightsPerCell : ForwardLightDataISR.MaxCulledLightsPerCell ;
#else
return ForwardLightData.MaxCulledLightsPerCell ;
#endif
}
struct FCulledLightsGridData
{
uint NumLocalLights;
uint DataStartIndex;
};
FCulledLightsGridData GetCulledLightsGrid(uint GridIndex, uint EyeIndex)
{
FCulledLightsGridData Result;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
BRANCH
if (EyeIndex == 0)
{
#endif
Result.NumLocalLights = min(ForwardLightData.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 0], ForwardLightData.NumLocalLights);
Result.DataStartIndex = ForwardLightData.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 1];
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
}
else
{
Result.NumLocalLights = min(ForwardLightDataISR.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 0], ForwardLightDataISR.NumLocalLights);
Result.DataStartIndex = ForwardLightDataISR.NumCulledLightsGrid[GridIndex * NUM_CULLED_LIGHTS_GRID_STRIDE + 1];
}
#endif
return Result;
}
struct FVirtualShadowMapSMRTSettings
{
int RayCount;
int SamplesPerRay;
float RayLengthScale;
float ScreenRayLength;
float CotMaxRayAngleFromLight;
float TexelDitherScale;
float ExtrapolateSlope;
float MaxSlopeBias;
uint AdaptiveRayCount;
};
FVirtualShadowMapSMRTSettings GetDirectionalLightSMRTSettings()
{
FVirtualShadowMapSMRTSettings Out;
Out.ScreenRayLength = ForwardLightData.DirectionalLightSMRTSettings.ScreenRayLength;
Out.RayCount = ForwardLightData.DirectionalLightSMRTSettings.SMRTRayCount;
Out.SamplesPerRay = ForwardLightData.DirectionalLightSMRTSettings.SMRTSamplesPerRay;
Out.RayLengthScale = ForwardLightData.DirectionalLightSMRTSettings.SMRTRayLengthScale;
Out.CotMaxRayAngleFromLight = ForwardLightData.DirectionalLightSMRTSettings.SMRTCotMaxRayAngleFromLight;
Out.TexelDitherScale = ForwardLightData.DirectionalLightSMRTSettings.SMRTTexelDitherScale;
Out.ExtrapolateSlope = ForwardLightData.DirectionalLightSMRTSettings.SMRTExtrapolateSlope;
Out.MaxSlopeBias = ForwardLightData.DirectionalLightSMRTSettings.SMRTMaxSlopeBias;
Out.AdaptiveRayCount = ForwardLightData.DirectionalLightSMRTSettings.SMRTAdaptiveRayCount;
return Out;
}
FDirectionalLightData GetDirectionalLightData(uint EyeIndex)
{
FDirectionalLightData Result;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
BRANCH
if (EyeIndex == 0)
{
#endif
Result.HasDirectionalLight = ForwardLightData.HasDirectionalLight;
Result.DirectionalLightShadowMapChannelMask = ForwardLightData.DirectionalLightShadowMapChannelMask;
Result.DirectionalLightDistanceFadeMAD = ForwardLightData.DirectionalLightDistanceFadeMAD;
Result.DirectionalLightColor = ForwardLightData.DirectionalLightColor;
Result.DirectionalLightDirection = ForwardLightData.DirectionalLightDirection;
Result.DirectionalLightSourceRadius = ForwardLightData.DirectionalLightSourceRadius;
Result.DirectionalLightSoftSourceRadius = ForwardLightData.DirectionalLightSoftSourceRadius;
Result.DirectionalLightSpecularScale = ForwardLightData.DirectionalLightSpecularScale;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
}
else
{
Result.HasDirectionalLight = ForwardLightDataISR.HasDirectionalLight;
Result.DirectionalLightShadowMapChannelMask = ForwardLightDataISR.DirectionalLightShadowMapChannelMask;
Result.DirectionalLightDistanceFadeMAD = ForwardLightDataISR.DirectionalLightDistanceFadeMAD;
Result.DirectionalLightColor = ForwardLightDataISR.DirectionalLightColor;
Result.DirectionalLightDirection = ForwardLightDataISR.DirectionalLightDirection;
Result.DirectionalLightSourceRadius = ForwardLightDataISR.DirectionalLightSourceRadius;
Result.DirectionalLightSoftSourceRadius = ForwardLightDataISR.DirectionalLightSoftSourceRadius;
Result.DirectionalLightSpecularScale = ForwardLightDataISR.DirectionalLightSpecularScale;
}
#endif
return Result;
}
FLocalLightData GetLocalLightData_Internal(
uint LocalLightIndex,
uint ClusteredDeferredSupportedEndIndex,
uint LumenSupportedStartIndex,
uint SimpleLightsEndIndex,
float4 InData0, float4 InData1, float4 InData2, float4 InData3, float4 InData4, float4 InData5)
{
FLocalLightData Out = (FLocalLightData)0;
Out.bClusteredDeferredSupported = LocalLightIndex < ClusteredDeferredSupportedEndIndex;
Out.bLumenLightSupported = LocalLightIndex >= LumenSupportedStartIndex;
Out.bIsSimpleLight = LocalLightIndex < SimpleLightsEndIndex;
Out.LightPositionAndInvRadius = InData0;
Out.LightColorAndIdAndFalloffExponent = InData1;
Out.LightDirectionAndShadowMask = InData2;
Out.SpotAnglesAndSourceRadiusPacked = InData3;
Out.LightTangentAndIESDataAndSpecularScale = InData4;
Out.RectDataAndVirtualShadowMapId = InData5;
Out.VirtualShadowMapId = int(Out.RectDataAndVirtualShadowMapId.z);
Out.LightSceneId = int(Out.LightColorAndIdAndFalloffExponent.z);
return Out;
}
FLocalLightData GetLocalLightDataNonStereo(uint LocalLightIndex)
{
FLocalLightData Out;
uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE;
Out = GetLocalLightData_Internal(
LocalLightIndex,
ForwardLightData.ClusteredDeferredSupportedEndIndex,
ForwardLightData.LumenSupportedStartIndex,
ForwardLightData.SimpleLightsEndIndex,
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 0],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 1],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 2],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 3],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 4],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 5]);
return Out;
}
FLocalLightData GetLocalLightData(uint GridIndex, uint EyeIndex)
{
FLocalLightData Out;
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
BRANCH
if (EyeIndex == 0)
{
#endif
uint LocalLightIndex = GetCulledLightDataGrid(GridIndex);
uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE;
Out = GetLocalLightData_Internal(
LocalLightIndex,
ForwardLightData.ClusteredDeferredSupportedEndIndex,
ForwardLightData.LumenSupportedStartIndex,
ForwardLightData.SimpleLightsEndIndex,
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 0],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 1],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 2],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 3],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 4],
ForwardLightData.ForwardLocalLightBuffer[LocalLightBaseIndex + 5]);
#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
}
else
{
uint LocalLightIndex = GetCulledLightDataGridISR(GridIndex);
uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE;
Out = GetLocalLightData_Internal(
LocalLightIndex,
ForwardLightDataISR.ClusteredDeferredSupportedEndIndex,
ForwardLightDataISR.LumenSupportedStartIndex,
ForwardLightDataISR.SimpleLightsEndIndex,
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 0],
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 1],
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 2],
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 3],
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 4],
ForwardLightDataISR.ForwardLocalLightBuffer[LocalLightBaseIndex + 5]);
}
#endif
return Out;
}
/**
* Helpers to pack/unpack the shadow mask for cluster shading and virtual shadow map
* Currently hard-coded for 4 bits per light, up to 32 lights per pixel in a uint4
*/
uint4 InitializePackedShadowMask()
{
return uint(0xffffffff).xxxx;
}
uint GetPackedShadowMaskMaxLightCount()
{
return VirtualShadowMap.PackedShadowMaskMaxLightCount;
}
void PackShadowMask(inout uint4 InOutShadowMask, float InShadowFactor, uint InLightIndex)
{
uint Value = ~uint(round(InShadowFactor * 15.0f)) & 15U;
uint Dword = InLightIndex / 8;
InOutShadowMask.x ^= (Dword == 0U) ? (Value << (InLightIndex ) * 4U) : 0U;
InOutShadowMask.y ^= (Dword == 1U) ? (Value << (InLightIndex - 8U) * 4U) : 0U;
InOutShadowMask.z ^= (Dword == 2U) ? (Value << (InLightIndex - 16U) * 4U) : 0U;
InOutShadowMask.w ^= (Dword == 3U) ? (Value << (InLightIndex - 24U) * 4U) : 0U;
//OutShadowMask ^= (~uint(round(InShadowFactor * 7.0)) & 7u) << (InLightIndex * 3u);
}
float UnpackShadowMask(uint4 InShadowMask, uint InLightIndex)
{
uint Dword = InLightIndex / 8;
return ((InShadowMask[Dword] >> (InLightIndex - Dword*8U) * 4U) & 15U) / 15.0f;
//return ((InShadowMask >> (InLightIndex * 3u)) & 7u) / 7.0;
}
// Unpack with dither to hide some of the quantization
float UnpackShadowMask(uint4 InShadowMask, uint InLightIndex, float Dither)
{
float ShadowFactor = UnpackShadowMask(InShadowMask, InLightIndex);
if (ShadowFactor > 0.0f && ShadowFactor < 1.0f)
{
ShadowFactor = saturate(ShadowFactor + (Dither - 0.5f) * (1.0f / 16.0f));
}
return ShadowFactor;
}