Skip to content

Commit d744b58

Browse files
vincent-breysseEvergreen
authored andcommitted
Optimize OnDemand shadow maps rendering
This PR is adressing 3 tickets : - Wrong sets of culled objects are rendered with OnDemand shadow rendering https://jira.unity3d.com/browse/UUM-60823 - Expensive Culling for Non-Rendered Shadow Cascades https://jira.unity3d.com/browse/UUM-60917 - Use-after-free causing a crash under certain conditions https://jira.unity3d.com/browse/UUM-68625 The first ticket is a bug. Some shadow casters are culled when they shouldn't. The second ticket is a performance improvement. It allows some culling jobs not to be kicked at all when no shadow map update is needed for a given light. E.g when using OnDemand or OnEnable shadow rendering mode and no update was requested. It is also speeding up culling jobs by skipping receiver sphere culling for the shadow cascade which do not need an update. Implementation keypoints: - Fix the splitIndex not being passed to ShadowDrawingSettings. Simply store the splitIndex HDShadowCullingSplit and retrieve it when building the ShadowDrawingSettings - Refactor shadow caching code so that we know at culling time if a shadow cache will need to be updated or not - Discard culling jobs for the lights which have no shadow maps to update at all (and does not have the draw dynamic checkbox enabled) - Add support for a new `splitExclusionMask` API which allows SRP code to tell if culling should be skipped for some cascades (e.g. because of shadow caching) - Use the `splitExclusionMask` value internally to skip receiver sphere culling on C++ side - Pass the `splitExclusionMask` value to BRG OnPerformCulling callback so that EG, GRD or any BRG user code can beneficiate from it
1 parent 13e03b3 commit d744b58

File tree

10 files changed

+395
-339
lines changed

10 files changed

+395
-339
lines changed

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDGpuLightsBuilder.LightLoop.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,6 @@ internal unsafe void UpdateShadowRequestsAndCalculateShadowIndices(
488488
NativeBitArray shadowRequestValidityArray = visibleLights.shadowRequestValidityArray;
489489

490490
HDShadowManagerDataForShadowRequestUpateJob shadowManagerData = default;
491-
shadowManagerData.cachedShadowManager.cachedDirectionalAngles = m_CachedDirectionalAnglesArray;
492491
shadowManager.GetUnmanageDataForShadowRequestJobs(ref shadowManagerData);
493492

494493
bool usesReversedZBuffer = SystemInfo.usesReversedZBuffer;
@@ -575,8 +574,6 @@ internal unsafe void UpdateShadowRequestsAndCalculateShadowIndices(
575574

576575
shadowRequestsAndIndicesJob.Run();
577576

578-
HDCachedShadowManager.instance.SetCachedDirectionalAngles(m_CachedDirectionalAnglesArray.Value);
579-
580577
ref UnsafeList<ShadowRequestIntermediateUpdateData> cachedDirectionalUpdateInfos = ref *(m_CachedDirectionalUpdateInfos.GetUnsafeList());
581578
int cachedDirectionalCount = cachedDirectionalUpdateInfos.Length;
582579
ref UnsafeList<ShadowRequestIntermediateUpdateData> dynamicDirectionalUpdateInfos = ref *(m_DynamicDirectionalUpdateInfos.GetUnsafeList());

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDGpuLightsBuilder.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,6 @@ public void Cleanup()
128128
m_DynamicDirectionalUpdateInfos.Dispose();
129129
}
130130

131-
if (m_CachedDirectionalAnglesArray.IsCreated)
132-
{
133-
m_CachedDirectionalAnglesArray.Dispose();
134-
}
135-
136131
if (m_ShadowIndicesScratchpadArray.IsCreated)
137132
{
138133
m_ShadowIndicesScratchpadArray.Dispose();
@@ -208,7 +203,6 @@ internal enum GPULightTypeCountSlots
208203
private NativeList<ShadowRequestIntermediateUpdateData> m_DynamicSpotUpdateInfos = new NativeList<ShadowRequestIntermediateUpdateData>(Allocator.Persistent);
209204
private NativeList<ShadowRequestIntermediateUpdateData> m_DynamicAreaRectangleUpdateInfos = new NativeList<ShadowRequestIntermediateUpdateData>(Allocator.Persistent);
210205
private NativeList<ShadowRequestIntermediateUpdateData> m_DynamicDirectionalUpdateInfos = new NativeList<ShadowRequestIntermediateUpdateData>(Allocator.Persistent);
211-
private NativeReference<Unity.Mathematics.float3> m_CachedDirectionalAnglesArray = new NativeReference<float3>(Allocator.Persistent);
212206

213207
private void AllocateLightData(int lightCount, int directionalLightCount)
214208
{
@@ -266,11 +260,6 @@ private void EnsureScratchpadCapacity(int lightCount)
266260
m_DynamicAreaRectangleUpdateInfos = new NativeList<ShadowRequestIntermediateUpdateData>(Allocator.Persistent);
267261
m_DynamicDirectionalUpdateInfos = new NativeList<ShadowRequestIntermediateUpdateData>(Allocator.Persistent);
268262
}
269-
270-
if (!m_CachedDirectionalAnglesArray.IsCreated)
271-
{
272-
m_CachedDirectionalAnglesArray = new NativeReference<float3>(Allocator.Persistent);
273-
}
274263
}
275264

276265
#endregion

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDLightRenderDatabase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ public bool updateUponLightMovement
133133
set => flags[UpdateUponLightMovementFlagsIndex] = value;
134134
}
135135

136+
public bool hasCachedComponent => shadowUpdateMode != ShadowUpdateMode.EveryFrame;
137+
136138
public void Set(HDAdditionalLightData additionalLightData)
137139
{
138140
shadowNearPlane = additionalLightData.shadowNearPlane;

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDProcessedVisibleLightsBuilder.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ internal struct ShadowIndicesAndVisibleLightData
2525
public int dataIndex;
2626
public int lightIndex;
2727
public HDShadowRequestSetHandle shadowRequestSetHandle;
28-
public LightType lightType;
2928
public int splitCount;
30-
public int shadowRequestCount;
3129
public int sortKeyIndex;
32-
public BitArray8 isSplitValidArray;
30+
public ShadowMapUpdateType shadowUpdateType;
31+
public BitArray8 isSplitValidMask;
32+
public BitArray8 needCacheUpdateMask;
33+
34+
public bool HasShadowCacheUpToDate(int splitIndex) => shadowUpdateType == ShadowMapUpdateType.Cached && !needCacheUpdateMask[(uint)splitIndex];
3335
}
3436

3537
//Class representing lights in the context of a view.

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDShadowRequestUpdateJob.cs

Lines changed: 36 additions & 106 deletions
Large diffs are not rendered by default.

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowManager.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ public class HDCachedShadowManager
2222

2323
// Data for cached directional light shadows.
2424
private const int m_MaxShadowCascades = 4;
25-
private BitArray8 directionalShadowPendingUpdate;
26-
private BitArray8 directionalShadowHasRendered;
27-
private Vector3 m_CachedDirectionalForward;
28-
private float3 m_CachedDirectionalAngles;
25+
private BitArray8 m_DirectionalShadowHasRendered;
26+
private BitArray8 m_DirectionalShadowPendingUpdate;
2927
private bool m_AllowDirectionalMixedCached = false;
3028

29+
internal BitArray8 directionalShadowPendingUpdate => m_DirectionalShadowPendingUpdate;
30+
internal float3 cachedDirectionalAngles;
31+
3132
internal const int k_MinSlotSize = 64;
3233

3334
// Helper array used to check what has been tmp filled.
@@ -193,7 +194,7 @@ public bool LightHasBeenPlaceAndRenderedAtLeastOnce(HDAdditionalLightData lightD
193194
bool hasRendered = true;
194195
for (int i = 0; i < numberOfCascades; ++i)
195196
{
196-
hasRendered = hasRendered && directionalShadowHasRendered[(uint)i];
197+
hasRendered = hasRendered && m_DirectionalShadowHasRendered[(uint)i];
197198
}
198199
return !lightData.ShadowIsUpdatedEveryFrame() && hasRendered;
199200
}
@@ -226,7 +227,7 @@ public bool ShadowHasBeenPlaceAndRenderedAtLeastOnce(HDAdditionalLightData light
226227
if (lightType == LightType.Directional)
227228
{
228229
Debug.Assert(shadowIndex < m_MaxShadowCascades, "Shadow Index is bigger than the maximum cascades allowed");
229-
return !lightData.ShadowIsUpdatedEveryFrame() && directionalShadowHasRendered[(uint)shadowIndex];
230+
return !lightData.ShadowIsUpdatedEveryFrame() && m_DirectionalShadowHasRendered[(uint)shadowIndex];
230231
}
231232

232233
return false;
@@ -238,8 +239,8 @@ private void MarkAllDirectionalShadowsForUpdate()
238239
{
239240
for (int i = 0; i < m_MaxShadowCascades; ++i)
240241
{
241-
directionalShadowPendingUpdate[(uint)i] = true;
242-
directionalShadowHasRendered[(uint)i] = false;
242+
m_DirectionalShadowPendingUpdate[(uint)i] = true;
243+
m_DirectionalShadowHasRendered[(uint)i] = false;
243244
}
244245
}
245246

@@ -289,11 +290,6 @@ internal bool DirectionalHasCachedAtlas()
289290
return m_AllowDirectionalMixedCached;
290291
}
291292

292-
internal void SetCachedDirectionalAngles(float3 angles)
293-
{
294-
m_CachedDirectionalAngles = angles;
295-
}
296-
297293
internal void UpdateDirectionalCacheTexture(RenderGraph renderGraph)
298294
{
299295
TextureHandle cacheHandle = directionalLightAtlas.GetOutputTexture(renderGraph);
@@ -357,7 +353,7 @@ internal void RegisterTransformToCache(HDAdditionalLightData lightData)
357353
if (ShaderConfig.s_AreaLights == 1 && lightType.IsArea())
358354
areaShadowAtlas.RegisterTransformCacheSlot(lightData);
359355
if (lightType == LightType.Directional)
360-
m_CachedDirectionalAngles = lightData.transform.eulerAngles;
356+
cachedDirectionalAngles = lightData.transform.eulerAngles;
361357
}
362358

363359
internal void AssignSlotsInAtlases()
@@ -369,8 +365,8 @@ internal void AssignSlotsInAtlases()
369365

370366
internal void MarkDirectionalShadowAsRendered(int shadowIdx)
371367
{
372-
directionalShadowPendingUpdate[(uint)shadowIdx] = false;
373-
directionalShadowHasRendered[(uint)shadowIdx] = true;
368+
m_DirectionalShadowPendingUpdate[(uint)shadowIdx] = false;
369+
m_DirectionalShadowHasRendered[(uint)shadowIdx] = true;
374370
}
375371

376372
internal void OverrideShadowResolutionRequestWithCachedData(ref HDShadowResolutionRequest request, int shadowIdx, ShadowMapType shadowMapType)
@@ -420,7 +416,7 @@ internal void ScheduleShadowUpdate(HDAdditionalLightData light, int subShadowInd
420416
if (lightType == LightType.Directional)
421417
{
422418
Debug.Assert(subShadowIndex < m_MaxShadowCascades);
423-
directionalShadowPendingUpdate[(uint)subShadowIndex] = true;
419+
m_DirectionalShadowPendingUpdate[(uint)subShadowIndex] = true;
424420
}
425421
}
426422

@@ -437,15 +433,14 @@ internal bool LightIsPendingPlacement(int lightIdxForCachedShadows, ShadowMapTyp
437433
internal void GetUnmanagedDataForShadowRequestJobs(ref HDCachedShadowManagerDataForShadowRequestUpdateJob dataForShadowRequestUpdateJob)
438434
{
439435

440-
dataForShadowRequestUpdateJob.directionalShadowPendingUpdate = directionalShadowPendingUpdate;
436+
dataForShadowRequestUpdateJob.directionalShadowPendingUpdate = m_DirectionalShadowPendingUpdate;
441437
punctualShadowAtlas.GetUnmanageDataForShadowRequestJobs(ref dataForShadowRequestUpdateJob.punctualShadowAtlas);
442438
if (ShaderConfig.s_AreaLights == 1)
443439
areaShadowAtlas.GetUnmanageDataForShadowRequestJobs(ref dataForShadowRequestUpdateJob.areaShadowAtlas);
444440
else
445441
dataForShadowRequestUpdateJob.areaShadowAtlas = emptyAreaShadowAtlasJob;
446442

447443
dataForShadowRequestUpdateJob.directionalLightAtlas.shadowRequests = directionalLightAtlas.m_ShadowRequests;
448-
dataForShadowRequestUpdateJob.cachedDirectionalAngles.Value = m_CachedDirectionalAngles;
449444
dataForShadowRequestUpdateJob.directionalHasCachedAtlas = DirectionalHasCachedAtlas();
450445
}
451446

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDShadowAtlas.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@ internal unsafe TextureHandle RenderShadowMaps(RenderGraph renderGraph, CullingR
419419
{
420420
ref var shadowRequest = ref requestStorageUnsafe.ElementAt(shadowRequestHandle.storageIndexForShadowRequest);
421421
var commonState = CommonPerShadowRequestUpdate(ctx.cmd, data, shadowRequest, shadowRequestHandle, ref planesScratchpad, ref frustumPlanesStorageUnsafe);
422-
423422
if (commonState.shouldSkipRequest)
424423
continue;
425424

@@ -439,6 +438,7 @@ internal unsafe TextureHandle RenderShadowMaps(RenderGraph renderGraph, CullingR
439438
CoreUtils.DrawFullScreen(ctx.cmd, data.clearMaterial, null, 0);
440439

441440
data.shadowDrawSettings.lightIndex = shadowRequest.lightIndex;
441+
data.shadowDrawSettings.splitIndex = shadowRequest.cullingSplit.splitIndex;
442442

443443
//TODO(ddebaets) as the shadowDrawSettings are modified in this loop, we generate this RL very last minute
444444
// We might want to refactor this and create the RL ahead of time (especially if we ever allow AsyncPrepare on them)

0 commit comments

Comments
 (0)