using System; using System.ComponentModel; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Mathematics; using Unity.Profiling; namespace UnityEngine.Rendering.HighDefinition { [BurstCompile] [NoAlias] internal unsafe struct HDShadowRequestUpdateJob : IJob { public HDShadowManagerDataForShadowRequestUpateJob shadowManager; [Unity.Collections.ReadOnly] public NativeBitArray shadowRequestValidityArray; [Unity.Collections.ReadOnly] public NativeArray sortKeys; [Unity.Collections.ReadOnly] public NativeArray visibleLightEntityDataIndices; [Unity.Collections.ReadOnly] public NativeArray processedEntities; [Unity.Collections.ReadOnly] public NativeArray visibleLights; [Unity.Collections.ReadOnly] public NativeList requestIndicesStorage; [Unity.Collections.ReadOnly] public NativeArray additionalLightDataUpdateInfos; [Unity.Collections.ReadOnly] public NativeArray visibleLightsAndIndicesBuffer; [Unity.Collections.ReadOnly] public UnsafeList cachedPointVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList cachedSpotVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList cachedAreaRectangleVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList cachedDirectionalVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList dynamicPointVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList dynamicSpotVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList dynamicAreaRectangleVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList dynamicDirectionalVisibleLightsAndIndices; [Unity.Collections.ReadOnly] public UnsafeList dynamicPointHDSplits; [Unity.Collections.ReadOnly] public UnsafeList cachedPointHDSplits; [Unity.Collections.ReadOnly] public UnsafeList dynamicSpotHDSplits; [Unity.Collections.ReadOnly] public UnsafeList cachedSpotHDSplits; [Unity.Collections.ReadOnly] public UnsafeList dynamicAreaRectangleHDSplits; [Unity.Collections.ReadOnly] public UnsafeList cachedAreaRectangleHDSplits; [Unity.Collections.ReadOnly] public UnsafeList dynamicDirectionalHDSplits; [Unity.Collections.ReadOnly] public UnsafeList cachedDirectionalHDSplits; public NativeList requestStorage; public NativeList cachedPointUpdateInfos; public NativeList cachedSpotUpdateInfos; public NativeList cachedAreaRectangleUpdateInfos; public NativeList cachedDirectionalUpdateInfos; public NativeList dynamicPointUpdateInfos; public NativeList dynamicSpotUpdateInfos; public NativeList dynamicAreaRectangleUpdateInfos; public NativeList dynamicDirectionalUpdateInfos; public NativeList frustumPlanesStorage; public NativeList cachedViewPositionsStorage; public NativeArray shadowIndices; #if UNITY_EDITOR [WriteOnly] public NativeArray shadowRequestCounts; #endif [Unity.Collections.ReadOnly] public int lightCounts; [Unity.Collections.ReadOnly] public int shadowSettingsCascadeShadowSplitCount; [Unity.Collections.ReadOnly] public Vector3 worldSpaceCameraPos; [Unity.Collections.ReadOnly] public int shaderConfigCameraRelativeRendering; [Unity.Collections.ReadOnly] public int shadowRequestCount; [Unity.Collections.ReadOnly] public HDShadowFilteringQuality punctualShadowFilteringQuality; [Unity.Collections.ReadOnly] public HDShadowFilteringQuality directionalShadowFilteringQuality; [Unity.Collections.ReadOnly] public bool usesReversedZBuffer; public ProfilerMarker cachedDirectionalRequestsMarker; public ProfilerMarker dynamicDirectionalRequestsMarker; public ProfilerMarker dynamicPointRequestsMarker; public ProfilerMarker dynamicSpotRequestsMarker; public ProfilerMarker dynamicAreaRectangleRequestsMarker; public ProfilerMarker cachedPointRequestsMarker; public ProfilerMarker cachedSpotRequestsMarker; public ProfilerMarker cachedAreaRectangleRequestsMarker; public void Execute() { // Write the first relevant shadow index to the shadowIndices buffer, one of this job's outputs. // The value may get overwritten later in the job with -1 if the request does not have atlas placement, // but we don't know which shadows do or don't have atlas placement yet. // We may want to extract this and the overwriting to a different set of loops in future iterations. for (int sortKeyIndex = 0; sortKeyIndex < lightCounts; sortKeyIndex++) { int shadowRequestCount = 0; int firstShadowRequestIndex = -1; if (shadowRequestValidityArray.IsSet(sortKeyIndex)) { uint sortKey = sortKeys[sortKeyIndex]; int lightIndex = (int)(sortKey & 0xFFFF); ShadowIndicesAndVisibleLightData visibleLightsAndIndices = visibleLightsAndIndicesBuffer[lightIndex]; HDShadowRequestSetHandle shadowRequestSetHandle = visibleLightsAndIndices.shadowRequestSetHandle; for (int index = 0; index < visibleLightsAndIndices.splitCount; index++) { if (!visibleLightsAndIndices.isSplitValidMask[(uint)index]) continue; HDShadowRequestHandle shadowRequestIndexLocation = shadowRequestSetHandle[index]; int shadowRequestIndex = requestIndicesStorage[shadowRequestIndexLocation.storageIndexForRequestIndex]; shadowManager.shadowRequests[shadowRequestIndex] = shadowRequestIndexLocation; // Store the first shadow request id to return it if (firstShadowRequestIndex == -1) firstShadowRequestIndex = shadowRequestIndex; } shadowRequestCount = visibleLightsAndIndices.splitCount; } #if UNITY_EDITOR shadowRequestCounts[sortKeyIndex] = shadowRequestCount; #endif shadowIndices[sortKeyIndex] = firstShadowRequestIndex; } // Perform two loops for each combination of light type and atlas associativity. // In the first loop, we get all the atlas-related work out of the way. // In the second, we do the heavier ALU work for shadow requests with matrix math etc. // Note: some of the work for directional lights is still managed, and so we do it after this job completes. using (cachedDirectionalRequestsMarker.Auto()) { for (int i = 0; i < cachedDirectionalVisibleLightsAndIndices.Length; i++) { ref ShadowIndicesAndVisibleLightData shadowIndicesAndVisibleLightData = ref cachedDirectionalVisibleLightsAndIndices.ElementAt(i); HDShadowRequestSetHandle shadowRequestSetHandle = shadowIndicesAndVisibleLightData.shadowRequestSetHandle; ShadowMapUpdateType cachedDirectionalUpdateType = shadowIndicesAndVisibleLightData.shadowUpdateType; BitArray8 needCacheUpdateMask = shadowIndicesAndVisibleLightData.needCacheUpdateMask; int lightIdxForCachedShadows = shadowIndicesAndVisibleLightData.additionalLightUpdateInfo.lightIdxForCachedShadows; bool shadowHasAtlasPlacement = lightIdxForCachedShadows != -1; if (!shadowHasAtlasPlacement) shadowIndices[shadowIndicesAndVisibleLightData.sortKeyIndex] = -1; for (int index = 0; index < shadowIndicesAndVisibleLightData.splitCount; index++) { if (!shadowIndicesAndVisibleLightData.isSplitValidMask[(uint)index]) continue; bool needToUpdateCachedContent = needCacheUpdateMask[(uint)index]; HDShadowRequestHandle indexHandle = shadowRequestSetHandle[index]; int shadowRequestIndex = requestIndicesStorage[indexHandle.storageIndexForRequestIndex]; ref HDShadowResolutionRequest resolutionRequest = ref shadowManager.shadowResolutionRequestStorage.ElementAt(shadowRequestIndex); ref var shadowRequest = ref requestStorage.ElementAt(indexHandle.storageIndexForShadowRequest); shadowRequest.isInCachedAtlas = cachedDirectionalUpdateType == ShadowMapUpdateType.Cached; shadowRequest.isMixedCached = cachedDirectionalUpdateType == ShadowMapUpdateType.Mixed; shadowRequest.shouldUseCachedShadowData = !needToUpdateCachedContent; shadowRequest.shadowMapType = ShadowMapType.CascadedDirectional; shadowRequest.dynamicAtlasViewport = resolutionRequest.dynamicAtlasViewport; shadowRequest.cachedAtlasViewport = resolutionRequest.cachedAtlasViewport; int updateDataListIndex = cachedDirectionalUpdateInfos.Length; cachedDirectionalUpdateInfos.Length = updateDataListIndex + 1; ref ShadowRequestIntermediateUpdateData updateInfo = ref cachedDirectionalUpdateInfos.ElementAt(updateDataListIndex); updateInfo.states[ShadowRequestIntermediateUpdateData.k_HasCachedComponent] = true; updateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent] = needToUpdateCachedContent; updateInfo.shadowRequestHandle = shadowRequestSetHandle[index]; updateInfo.additionalLightDataIndex = shadowIndicesAndVisibleLightData.dataIndex; updateInfo.updateType = cachedDirectionalUpdateType; updateInfo.viewportSize = resolutionRequest.resolution; updateInfo.lightIndex = shadowIndicesAndVisibleLightData.lightIndex; if (shadowRequestIndex < shadowRequestCount) { if (cachedDirectionalUpdateType == ShadowMapUpdateType.Mixed && shadowManager.cachedShadowManager.directionalHasCachedAtlas) { shadowManager.cachedShadowManager.directionalLightAtlas.shadowRequests.Add(shadowRequestSetHandle[index]); shadowManager.cascadeShadowAtlas.mixedRequestsPendingBlits.Add(shadowRequestSetHandle[index]); } shadowManager.cascadeShadowAtlas.shadowRequests.Add(shadowRequestSetHandle[index]); } } } } using (dynamicDirectionalRequestsMarker.Auto()) { for (int i = 0; i < dynamicDirectionalVisibleLightsAndIndices.Length; i++) { ref ShadowIndicesAndVisibleLightData shadowIndicesAndVisibleLightData = ref dynamicDirectionalVisibleLightsAndIndices.ElementAt(i); HDShadowRequestSetHandle shadowRequestSetHandle = shadowIndicesAndVisibleLightData.shadowRequestSetHandle; for (int index = 0; index < shadowIndicesAndVisibleLightData.splitCount; index++) { if (!shadowIndicesAndVisibleLightData.isSplitValidMask[(uint)index]) continue; HDShadowRequestHandle indexHandle = shadowRequestSetHandle[index]; int shadowRequestIndex = requestIndicesStorage[indexHandle.storageIndexForRequestIndex]; ref HDShadowResolutionRequest resolutionRequest = ref shadowManager.shadowResolutionRequestStorage.ElementAt(shadowRequestIndex); ref var shadowRequest = ref requestStorage.ElementAt(indexHandle.storageIndexForShadowRequest); shadowRequest.isInCachedAtlas = false; shadowRequest.isMixedCached = false; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.shadowMapType = ShadowMapType.CascadedDirectional; shadowRequest.dynamicAtlasViewport = resolutionRequest.dynamicAtlasViewport; shadowRequest.cachedAtlasViewport = resolutionRequest.cachedAtlasViewport; int updateDataListIndex = dynamicDirectionalUpdateInfos.Length; dynamicDirectionalUpdateInfos.Length = updateDataListIndex + 1; ref ShadowRequestIntermediateUpdateData updateInfo = ref dynamicDirectionalUpdateInfos.ElementAt(updateDataListIndex); updateInfo.states[ShadowRequestIntermediateUpdateData.k_HasCachedComponent] = false; updateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent] = false; updateInfo.shadowRequestHandle = shadowRequestSetHandle[index]; updateInfo.additionalLightDataIndex = shadowIndicesAndVisibleLightData.dataIndex; updateInfo.updateType = ShadowMapUpdateType.Dynamic; updateInfo.viewportSize = resolutionRequest.resolution; updateInfo.lightIndex = shadowIndicesAndVisibleLightData.lightIndex; if (shadowRequestIndex < shadowRequestCount) shadowManager.cascadeShadowAtlas.shadowRequests.Add(shadowRequestSetHandle[index]); } } } // Update cached area rectangle: using (cachedAreaRectangleRequestsMarker.Auto()) { UpdateNonDirectionalCachedRequests(LightType.Rectangle, shadowManager.cachedShadowManager.areaShadowAtlas, shadowManager.areaShadowAtlas, cachedAreaRectangleVisibleLightsAndIndices, cachedAreaRectangleUpdateInfos, shadowIndices, shadowRequestCount); UpdateCachedAreaShadowRequestsAndResolutionRequests(cachedAreaRectangleUpdateInfos); } // Update cached point: using (cachedPointRequestsMarker.Auto()) { UpdateNonDirectionalCachedRequests(LightType.Point, shadowManager.cachedShadowManager.punctualShadowAtlas, shadowManager.atlas, cachedPointVisibleLightsAndIndices, cachedPointUpdateInfos, shadowIndices, shadowRequestCount); UpdateCachedPointShadowRequestsAndResolutionRequests(); } // Update cached spot: using (cachedSpotRequestsMarker.Auto()) { UpdateNonDirectionalCachedRequests(LightType.Spot, shadowManager.cachedShadowManager.punctualShadowAtlas, shadowManager.atlas, cachedSpotVisibleLightsAndIndices, cachedSpotUpdateInfos, shadowIndices, shadowRequestCount); UpdateCachedSpotShadowRequestsAndResolutionRequests(); } // Update dynamic area rectangle: using (dynamicAreaRectangleRequestsMarker.Auto()) { UpdateNonDirectionalDynamicRequests(LightType.Rectangle, shadowManager.cachedShadowManager.areaShadowAtlas, shadowManager.areaShadowAtlas, dynamicAreaRectangleVisibleLightsAndIndices, dynamicAreaRectangleUpdateInfos, shadowRequestCount); UpdateDynamicAreaShadowRequestsAndResolutionRequests(dynamicAreaRectangleUpdateInfos); } // Update dynamic point: using (dynamicPointRequestsMarker.Auto()) { UpdateNonDirectionalDynamicRequests(LightType.Point, shadowManager.cachedShadowManager.punctualShadowAtlas, shadowManager.atlas, dynamicPointVisibleLightsAndIndices, dynamicPointUpdateInfos, shadowRequestCount); UpdateDynamicPointShadowRequestsAndResolutionRequests(); } // Update dynamic point: using (dynamicSpotRequestsMarker.Auto()) { UpdateNonDirectionalDynamicRequests(LightType.Spot, shadowManager.cachedShadowManager.punctualShadowAtlas, shadowManager.atlas, dynamicSpotVisibleLightsAndIndices, dynamicSpotUpdateInfos, shadowRequestCount); UpdateDynamicSpotShadowRequestsAndResolutionRequests(); } } public void UpdateCachedPointShadowRequestsAndResolutionRequests() { int pointCount = cachedPointUpdateInfos.Length; for (int i = 0; i < pointCount; i++) { ref ShadowRequestIntermediateUpdateData pointUpdateInfo = ref cachedPointUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref cachedPointHDSplits.ElementAt(i); bool needToUpdateCachedContent = pointUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent]; bool hasCachedComponent = pointUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_HasCachedComponent]; HDShadowRequestHandle shadowRequestHandle = pointUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = pointUpdateInfo.additionalLightDataIndex; int lightIndex = pointUpdateInfo.lightIndex; Vector2 viewportSize = pointUpdateInfo.viewportSize; ShadowMapUpdateType updateType = pointUpdateInfo.updateType; bool isSampledFromCache = (updateType == ShadowMapUpdateType.Cached); bool needToUpdateDynamicContent = !isSampledFromCache; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; bool hasUpdatedRequestData = false; if (needToUpdateCachedContent) { cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition] = worldSpaceCameraPos; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetPointRequestSettings(ref shadowRequest, shadowRequestHandle, in pointUpdateInfo.visibleLight, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); hasUpdatedRequestData = true; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.shouldRenderCachedComponent = true; } else if (hasCachedComponent) { shadowRequest.cachedShadowData.cacheTranslationDelta = worldSpaceCameraPos - cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition]; shadowRequest.shouldUseCachedShadowData = true; shadowRequest.shouldRenderCachedComponent = false; } if (needToUpdateDynamicContent && !hasUpdatedRequestData) { shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetPointRequestSettings(ref shadowRequest, shadowRequestHandle, in pointUpdateInfo.visibleLight, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } } public void UpdateDynamicPointShadowRequestsAndResolutionRequests() { int pointCount = dynamicPointUpdateInfos.Length; for (int i = 0; i < pointCount; i++) { ref ShadowRequestIntermediateUpdateData pointUpdateInfo = ref dynamicPointUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref dynamicPointHDSplits.ElementAt(i); HDShadowRequestHandle shadowRequestHandle = pointUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = pointUpdateInfo.additionalLightDataIndex; int lightIndex = pointUpdateInfo.lightIndex; Vector2 viewportSize = pointUpdateInfo.viewportSize; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetPointRequestSettings(ref shadowRequest, shadowRequestHandle, in pointUpdateInfo.visibleLight, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } /// /// This method has a duplicate of the same name in HDGpuLightsBuilder.LightLoop.cs /// This was duplicated to support the expensive managed callback per spot light, without sacrificing performance in the Burst compiled job. /// Any changes made here should be duplicated in the other function and vice versa. /// public void UpdateCachedSpotShadowRequestsAndResolutionRequests() { int spotCount = cachedSpotUpdateInfos.Length; for (int i = 0; i < spotCount; i++) { ref ShadowRequestIntermediateUpdateData spotUpdateInfo = ref cachedSpotUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref cachedSpotHDSplits.ElementAt(i); bool needToUpdateCachedContent = spotUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent]; HDShadowRequestHandle shadowRequestHandle = spotUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = spotUpdateInfo.additionalLightDataIndex; int lightIndex = spotUpdateInfo.lightIndex; Vector2 viewportSize = spotUpdateInfo.viewportSize; ShadowMapUpdateType updateType = spotUpdateInfo.updateType; bool isSampledFromCache = (updateType == ShadowMapUpdateType.Cached); bool needToUpdateDynamicContent = !isSampledFromCache; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; bool hasUpdatedRequestData = false; if (needToUpdateCachedContent) { cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition] = worldSpaceCameraPos; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); hasUpdatedRequestData = true; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.shouldRenderCachedComponent = true; } else { shadowRequest.cachedShadowData.cacheTranslationDelta = worldSpaceCameraPos - cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition]; shadowRequest.shouldUseCachedShadowData = true; shadowRequest.shouldRenderCachedComponent = false; } if (needToUpdateDynamicContent && !hasUpdatedRequestData) { shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } } public void UpdateDynamicSpotShadowRequestsAndResolutionRequests() { int spotCount = dynamicSpotUpdateInfos.Length; for (int i = 0; i < spotCount; i++) { ref ShadowRequestIntermediateUpdateData spotUpdateInfo = ref dynamicSpotUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref dynamicSpotHDSplits.ElementAt(i); HDShadowRequestHandle shadowRequestHandle = spotUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = spotUpdateInfo.additionalLightDataIndex; int lightIndex = spotUpdateInfo.lightIndex; Vector2 viewportSize = spotUpdateInfo.viewportSize; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, punctualShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } public void UpdateCachedAreaShadowRequestsAndResolutionRequests(NativeList areaUpdateInfos) { int areaCount = areaUpdateInfos.Length; for (int i = 0; i < areaCount; i++) { ref ShadowRequestIntermediateUpdateData areaUpdateInfo = ref areaUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref cachedAreaRectangleHDSplits.ElementAt(i); bool needToUpdateCachedContent = areaUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent]; HDShadowRequestHandle shadowRequestHandle = areaUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = areaUpdateInfo.additionalLightDataIndex; int lightIndex = areaUpdateInfo.lightIndex; Vector2 viewportSize = areaUpdateInfo.viewportSize; VisibleLight visibleLight = visibleLights[lightIndex]; ShadowMapUpdateType updateType = areaUpdateInfo.updateType; bool isSampledFromCache = (updateType == ShadowMapUpdateType.Cached); bool needToUpdateDynamicContent = !isSampledFromCache; bool hasUpdatedRequestData = false; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; if (needToUpdateCachedContent) { cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition] = worldSpaceCameraPos; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetAreaRequestSettings(ref shadowRequest, shadowRequestHandle, visibleLight, shadowRequest.cullingSplit.forwardOffset, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, shadowManager.areaShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); hasUpdatedRequestData = true; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.shouldRenderCachedComponent = true; } else { shadowRequest.cachedShadowData.cacheTranslationDelta = worldSpaceCameraPos - cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition]; shadowRequest.shouldUseCachedShadowData = true; shadowRequest.shouldRenderCachedComponent = false; } if (needToUpdateDynamicContent && !hasUpdatedRequestData) { shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetAreaRequestSettings(ref shadowRequest, shadowRequestHandle, visibleLight, shadowRequest.cullingSplit.forwardOffset, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, shadowManager.areaShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } } public void UpdateDynamicAreaShadowRequestsAndResolutionRequests(NativeList areaUpdateInfos) { int areaCount = areaUpdateInfos.Length; for (int i = 0; i < areaCount; i++) { ref ShadowRequestIntermediateUpdateData areaUpdateInfo = ref areaUpdateInfos.ElementAt(i); ref HDShadowCullingSplit newShadowCullingSplit = ref dynamicAreaRectangleHDSplits.ElementAt(i); HDShadowRequestHandle shadowRequestHandle = areaUpdateInfo.shadowRequestHandle; ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex); int additionalLightDataIndex = areaUpdateInfo.additionalLightDataIndex; int lightIndex = areaUpdateInfo.lightIndex; Vector2 viewportSize = areaUpdateInfo.viewportSize; HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex]; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f); shadowRequest.cullingSplit = newShadowCullingSplit; HDGpuLightsBuilder.SetAreaRequestSettings(ref shadowRequest, shadowRequestHandle, areaUpdateInfo.visibleLight, shadowRequest.cullingSplit.forwardOffset, worldSpaceCameraPos, shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize, lightIndex, shadowManager.areaShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage); } } public void UpdateNonDirectionalCachedRequests(LightType lightType, HDCachedShadowAtlasDataForShadowRequestUpdateJob cachedShadowAtlas, HDDynamicShadowAtlasDataForShadowRequestUpdateJob dynamicShadowAtlas, UnsafeList visibleLightsAndIndices, NativeList updateDataList, NativeArray shadowIndices, int shadowManagerRequestCount) { for (int i = 0; i < visibleLightsAndIndices.Length; i++) { ref ShadowIndicesAndVisibleLightData shadowIndicesAndVisibleLightData = ref visibleLightsAndIndices.ElementAt(i); HDShadowRequestSetHandle shadowRequestSetHandle = shadowIndicesAndVisibleLightData.shadowRequestSetHandle; ShadowMapUpdateType updateType = shadowIndicesAndVisibleLightData.shadowUpdateType; BitArray8 needCacheUpdateMask = shadowIndicesAndVisibleLightData.needCacheUpdateMask; int lightIdxForCachedShadows = shadowIndicesAndVisibleLightData.additionalLightUpdateInfo.lightIdxForCachedShadows; // If we force evicted the light, it will have lightIdxForCachedShadows == -1 bool shadowHasAtlasPlacement = !(cachedShadowAtlas.registeredLightDataPendingPlacement.ContainsKey(lightIdxForCachedShadows) || cachedShadowAtlas.recordsPendingPlacement.ContainsKey(lightIdxForCachedShadows)) && lightIdxForCachedShadows != -1; if (!shadowHasAtlasPlacement) shadowIndices[shadowIndicesAndVisibleLightData.sortKeyIndex] = -1; for (int index = 0; index < shadowIndicesAndVisibleLightData.splitCount; index++) { if (!shadowIndicesAndVisibleLightData.isSplitValidMask[(uint)index]) continue; HDShadowRequestHandle indexHandle = shadowRequestSetHandle[index]; int shadowRequestIndex = requestIndicesStorage[indexHandle.storageIndexForRequestIndex]; ref HDShadowResolutionRequest resolutionRequest = ref shadowManager.shadowResolutionRequestStorage.ElementAt(shadowRequestIndex); bool needToUpdateCachedContent = needCacheUpdateMask[(uint)index]; ref var shadowRequest = ref requestStorage.ElementAt(indexHandle.storageIndexForShadowRequest); shadowRequest.isInCachedAtlas = updateType == ShadowMapUpdateType.Cached; shadowRequest.isMixedCached = updateType == ShadowMapUpdateType.Mixed; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.dynamicAtlasViewport = resolutionRequest.dynamicAtlasViewport; shadowRequest.cachedAtlasViewport = resolutionRequest.cachedAtlasViewport; int updateDataListIndex = updateDataList.Length; updateDataList.Length = updateDataListIndex + 1; ref ShadowRequestIntermediateUpdateData updateInfo = ref updateDataList.ElementAt(updateDataListIndex); updateInfo.visibleLight = shadowIndicesAndVisibleLightData.visibleLight; updateInfo.states[ShadowRequestIntermediateUpdateData.k_HasCachedComponent] = true; updateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent] = needToUpdateCachedContent; updateInfo.shadowRequestHandle = shadowRequestSetHandle[index]; updateInfo.additionalLightDataIndex = shadowIndicesAndVisibleLightData.dataIndex; updateInfo.updateType = updateType; updateInfo.viewportSize = resolutionRequest.resolution; updateInfo.lightIndex = shadowIndicesAndVisibleLightData.lightIndex; if (shadowRequestIndex < shadowManagerRequestCount) { bool addToCached = updateType == ShadowMapUpdateType.Cached || updateType == ShadowMapUpdateType.Mixed; bool addDynamic = updateType == ShadowMapUpdateType.Dynamic || updateType == ShadowMapUpdateType.Mixed; HDShadowRequestHandle shadowRequestHandle = shadowRequestSetHandle[index]; if (addToCached) cachedShadowAtlas.shadowRequests.Add(shadowRequestHandle); if (addDynamic) { dynamicShadowAtlas.shadowRequests.Add(shadowRequestHandle); if(updateType == ShadowMapUpdateType.Mixed) dynamicShadowAtlas.mixedRequestsPendingBlits.Add(shadowRequestHandle); } } } } } public void UpdateNonDirectionalDynamicRequests(LightType lightType, HDCachedShadowAtlasDataForShadowRequestUpdateJob cachedShadowAtlas, HDDynamicShadowAtlasDataForShadowRequestUpdateJob dynamicShadowAtlas, UnsafeList visibleLightsAndIndices, NativeList updateDataList, int shadowManagerRequestCount) { for (int i = 0; i < visibleLightsAndIndices.Length; i++) { ref ShadowIndicesAndVisibleLightData shadowIndicesAndVisibleLightData = ref visibleLightsAndIndices.ElementAt(i); HDShadowRequestSetHandle shadowRequestSetHandle = shadowIndicesAndVisibleLightData.shadowRequestSetHandle; for (int index = 0; index < shadowIndicesAndVisibleLightData.splitCount; index++) { if (!shadowIndicesAndVisibleLightData.isSplitValidMask[(uint)index]) continue; HDShadowRequestHandle indexHandle = shadowRequestSetHandle[index]; int shadowRequestIndex = requestIndicesStorage[indexHandle.storageIndexForRequestIndex]; ref HDShadowResolutionRequest resolutionRequest = ref shadowManager.shadowResolutionRequestStorage.ElementAt(shadowRequestIndex); ref var shadowRequest = ref requestStorage.ElementAt(indexHandle.storageIndexForShadowRequest); shadowRequest.isInCachedAtlas = false; shadowRequest.isMixedCached = false; shadowRequest.shouldUseCachedShadowData = false; shadowRequest.dynamicAtlasViewport = resolutionRequest.dynamicAtlasViewport; shadowRequest.cachedAtlasViewport = resolutionRequest.cachedAtlasViewport; int updateDataListIndex = updateDataList.Length; updateDataList.Length = updateDataListIndex + 1; ref ShadowRequestIntermediateUpdateData updateInfo = ref updateDataList.ElementAt(updateDataListIndex); updateInfo.visibleLight = shadowIndicesAndVisibleLightData.visibleLight; updateInfo.states[ShadowRequestIntermediateUpdateData.k_HasCachedComponent] = false; updateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent] = false; updateInfo.shadowRequestHandle = shadowRequestSetHandle[index]; updateInfo.additionalLightDataIndex = shadowIndicesAndVisibleLightData.dataIndex; updateInfo.updateType = ShadowMapUpdateType.Dynamic; updateInfo.viewportSize = resolutionRequest.resolution; updateInfo.lightIndex = shadowIndicesAndVisibleLightData.lightIndex; if (shadowRequestIndex < shadowManagerRequestCount) dynamicShadowAtlas.shadowRequests.Add(shadowRequestSetHandle[index]); } } } } internal struct ShadowRequestIntermediateUpdateData { public VisibleLight visibleLight; public HDShadowRequestHandle shadowRequestHandle; public int additionalLightDataIndex; public Vector2 viewportSize; public int lightIndex; public ShadowMapUpdateType updateType; public BitArray8 states; public const int k_HasCachedComponent = 0; public const int k_IsSampledFromCache = 1; public const int k_NeedsRenderingDueToTransformChange = 2; public const int k_ShadowHasAtlasPlacement = 3; public const int k_NeedToUpdateCachedContent = 4; } internal class ShadowRequestUpdateProfiling { internal static ProfilerMarker dynamicDirectionalRequestsMarker = new ProfilerMarker("UpdateDynamicDirectionalRequests"); internal static ProfilerMarker dynamicPointRequestsMarker = new ProfilerMarker("UpdateDynamicPointRequests"); internal static ProfilerMarker dynamicSpotRequestsMarker = new ProfilerMarker("UpdateDynamicSpotRequests"); internal static ProfilerMarker dynamicAreaRectangleRequestsMarker = new ProfilerMarker("UpdateDynamicAreaRectangleRequests"); internal static ProfilerMarker cachedDirectionalRequestsMarker = new ProfilerMarker("UpdateCachedDirectionalRequests"); internal static ProfilerMarker cachedPointRequestsMarker = new ProfilerMarker("UpdateCachedPointRequests"); internal static ProfilerMarker cachedSpotRequestsMarker = new ProfilerMarker("UpdateCachedSpotRequests"); internal static ProfilerMarker cachedAreaRectangleRequestsMarker = new ProfilerMarker("UpdateCachedAreaRectangleRequests"); } }