diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs index bb64826d..1792269b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs @@ -279,13 +279,6 @@ namespace UnityEditor.Rendering var supportedOn = volumeComponentType.GetCustomAttribute(); m_LegacyPipelineTypes = supportedOn != null ? supportedOn.pipelineTypes : Array.Empty(); #pragma warning restore CS0618 - - EditorApplication.contextualPropertyMenu += OnPropertyContextMenu; - } - - void OnDestroy() - { - EditorApplication.contextualPropertyMenu -= OnPropertyContextMenu; } internal void DetermineVisibility(Type renderPipelineAssetType, Type renderPipelineType) @@ -393,23 +386,13 @@ namespace UnityEditor.Rendering profile != null && defaultProfile != profile) { + menu.AddSeparator(string.Empty); menu.AddItem(EditorGUIUtility.TrTextContent($"Show Default Volume Profile"), false, () => Selection.activeObject = defaultProfile); menu.AddItem(EditorGUIUtility.TrTextContent($"Apply Values to Default Volume Profile"), false, copyAction); } } - void OnPropertyContextMenu(GenericMenu menu, SerializedProperty property) - { - if (property.serializedObject.targetObject != target) - return; - - var targetComponent = property.serializedObject.targetObject as VolumeComponent; - - AddDefaultProfileContextMenuEntries(menu, VolumeManager.instance.globalDefaultProfile, - () => VolumeProfileUtils.AssignValuesToProfile(VolumeManager.instance.globalDefaultProfile, targetComponent, property)); - } - /// /// Unity calls this method after drawing the header for each VolumeComponentEditor /// diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs index 47734b62..36eebd1b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs @@ -445,13 +445,14 @@ namespace UnityEditor.Rendering if (!m_IsDefaultVolumeProfile) menu.AddItem(EditorGUIUtility.TrTextContent("Remove"), false, () => RemoveComponent(id)); - menu.AddSeparator(string.Empty); if (targetEditor.hasAdditionalProperties) + { + menu.AddSeparator(string.Empty); menu.AddAdvancedPropertiesBoolMenuItem(() => targetEditor.showAdditionalProperties, () => targetEditor.showAdditionalProperties ^= true); + } - menu.AddSeparator(string.Empty); targetEditor.AddDefaultProfileContextMenuEntries(menu, VolumeManager.instance.globalDefaultProfile, () => VolumeProfileUtils.CopyValuesToProfile(targetComponent, VolumeManager.instance.globalDefaultProfile)); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs index 1df80681..773befe1 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using Unity.Collections; +#if UNITY_EDITOR +using UnityEditor; +#endif using static UnityEngine.Rendering.DebugUI; using static UnityEngine.Rendering.DebugUI.Widget; @@ -106,6 +109,7 @@ namespace UnityEngine.Rendering else return new InstanceOcclusionEventStats(); } + static class Strings { public const string drawerSettingsContainerName = "GPU Resident Drawer Settings"; @@ -144,6 +148,7 @@ namespace UnityEngine.Rendering { return GPUResidentDrawer.GetDebugStats()?.instanceOcclusionEventStats.Length ?? 0; } + private static DebugUI.Table.Row AddInstanceCullerViewDataRow(int viewIndex) { return new DebugUI.Table.Row @@ -154,9 +159,32 @@ namespace UnityEngine.Rendering children = { new DebugUI.Value { displayName = "View Type", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceCullerViewStats(viewIndex).viewType }, - new DebugUI.Value { displayName = "View Instance ID", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceCullerViewStats(viewIndex).viewInstanceID }, + new DebugUI.Value { displayName = "View Instance ID", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + var viewStats = GetInstanceCullerViewStats(viewIndex); +#if UNITY_EDITOR + Object view = EditorUtility.InstanceIDToObject(viewStats.viewInstanceID); + if (view) + { + return $"{viewStats.viewInstanceID} ({view.name})"; + } +#endif + return viewStats.viewInstanceID; + } + }, new DebugUI.Value { displayName = "Split Index", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceCullerViewStats(viewIndex).splitIndex }, - new DebugUI.Value { displayName = "Visible Instances", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceCullerViewStats(viewIndex).visibleInstances }, + new DebugUI.Value { displayName = "Visible Instances CPU | GPU", tooltip = "Visible instances after CPU culling and after GPU culling.", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + return $"{viewStats.visibleInstancesOnCPU} | {viewStats.visibleInstancesOnGPU}"; + } + }, + new DebugUI.Value { displayName = "Visible Primitives CPU | GPU", tooltip = "Visible primitives after CPU culling and after GPU culling.", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + return $"{viewStats.visiblePrimitivesOnCPU} | {viewStats.visiblePrimitivesOnGPU}"; + } + }, new DebugUI.Value { displayName = "Draw Commands", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceCullerViewStats(viewIndex).drawCommands }, } }; @@ -182,6 +210,16 @@ namespace UnityEngine.Rendering return (stats.eventType == InstanceOcclusionEventType.OcclusionTest) ? stats.culledInstances : "-"; } + private static object VisiblePrimitivesString(in InstanceOcclusionEventStats stats) + { + return (stats.eventType == InstanceOcclusionEventType.OcclusionTest) ? stats.visiblePrimitives : "-"; + } + + private static object CulledPrimitivesString(in InstanceOcclusionEventStats stats) + { + return (stats.eventType == InstanceOcclusionEventType.OcclusionTest) ? stats.culledPrimitives : "-"; + } + private static DebugUI.Table.Row AddInstanceOcclusionPassDataRow(int eventIndex) { return new DebugUI.Table.Row @@ -191,13 +229,27 @@ namespace UnityEngine.Rendering isHiddenCallback = () => { return eventIndex >= GetInstanceOcclusionEventCount(); }, children = { - new DebugUI.Value { displayName = "View Instance ID", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => GetInstanceOcclusionEventStats(eventIndex).viewInstanceID }, + new DebugUI.Value { displayName = "View Instance ID", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + var eventStats = GetInstanceOcclusionEventStats(eventIndex); +#if UNITY_EDITOR + Object view = EditorUtility.InstanceIDToObject(eventStats.viewInstanceID); + if (view) + { + return $"{eventStats.viewInstanceID} ({view.name})"; + } +#endif + return eventStats.viewInstanceID; + } + }, new DebugUI.Value { displayName = "Event Type", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => $"{GetInstanceOcclusionEventStats(eventIndex).eventType}" }, new DebugUI.Value { displayName = "Occluder Version", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => OccluderVersionString(GetInstanceOcclusionEventStats(eventIndex)) }, new DebugUI.Value { displayName = "Subview Mask", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => $"0x{GetInstanceOcclusionEventStats(eventIndex).subviewMask:X}" }, new DebugUI.Value { displayName = "Occlusion Test", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => $"{OcclusionTestString(GetInstanceOcclusionEventStats(eventIndex))}" }, new DebugUI.Value { displayName = "Visible Instances", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => VisibleInstancesString(GetInstanceOcclusionEventStats(eventIndex)) }, new DebugUI.Value { displayName = "Culled Instances", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => CulledInstancesString(GetInstanceOcclusionEventStats(eventIndex)) }, + new DebugUI.Value { displayName = "Visible Primitives", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => VisiblePrimitivesString(GetInstanceOcclusionEventStats(eventIndex)) }, + new DebugUI.Value { displayName = "Culled Primitives", refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => CulledPrimitivesString(GetInstanceOcclusionEventStats(eventIndex)) }, } }; } @@ -298,6 +350,104 @@ namespace UnityEngine.Rendering } }); + instanceCullerStats.children.Add(new DebugUI.ValueTuple() + { + displayName = "Total Visible Instances (Cameras | Lights | Both)", + values = new[] + { + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDInstances = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType == BatchCullingViewType.Camera) + totalGRDInstances += viewStats.visibleInstancesOnGPU; + } + return totalGRDInstances; + } + }, + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDInstances = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType == BatchCullingViewType.Light) + totalGRDInstances += viewStats.visibleInstancesOnGPU; + } + return totalGRDInstances; + } + }, + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDInstances = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType != BatchCullingViewType.Filtering + && viewStats.viewType != BatchCullingViewType.Picking + && viewStats.viewType != BatchCullingViewType.SelectionOutline) + totalGRDInstances += viewStats.visibleInstancesOnGPU; + } + return totalGRDInstances; + } + }, + } + }); + + instanceCullerStats.children.Add(new DebugUI.ValueTuple() + { + displayName = "Total Visible Primitives (Cameras | Lights | Both)", + values = new[] + { + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDPrimitives = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType == BatchCullingViewType.Camera) + totalGRDPrimitives += viewStats.visiblePrimitivesOnGPU; + } + return totalGRDPrimitives; + } + }, + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDPrimitives = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType == BatchCullingViewType.Light) + totalGRDPrimitives += viewStats.visiblePrimitivesOnGPU; + } + return totalGRDPrimitives; + } + }, + new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FormatString, getter = () => + { + int totalGRDPrimitives = 0; + + for (int viewIndex = 0; viewIndex < GetInstanceCullerViewCount(); viewIndex++) + { + var viewStats = GetInstanceCullerViewStats(viewIndex); + if (viewStats.viewType != BatchCullingViewType.Filtering + && viewStats.viewType != BatchCullingViewType.Picking + && viewStats.viewType != BatchCullingViewType.SelectionOutline) + totalGRDPrimitives += viewStats.visiblePrimitivesOnGPU; + } + return totalGRDPrimitives; + } + }, + } + }); + DebugUI.Table viewTable = new DebugUI.Table { displayName = "", diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs index 96e3591e..b5fdf4ec 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs @@ -530,7 +530,7 @@ namespace UnityEngine.Rendering rendererIDs[i] = renderers[i] ? renderers[i].GetInstanceID() : 0; m_Batcher.UpdateSelectedRenderers(rendererIDs); - + rendererIDs.Dispose(); Profiler.EndSample(); @@ -620,7 +620,7 @@ namespace UnityEngine.Rendering UpdateSelection(); m_IsSelectionDirty = false; } - + m_FrameUpdateNeeded = false; #endif } @@ -827,14 +827,8 @@ namespace UnityEngine.Rendering if (materials.Length > 0) { - new ClassifyMaterialsJob - { - materialIDs = materials.AsReadOnly(), - batchMaterialHash = m_Batcher.instanceCullingBatcher.batchMaterialHash.AsReadOnly(), - unsupportedMaterialIDs = unsupportedMaterials, - supportedMaterialIDs = supportedMaterials, - supportedPackedMaterialDatas = supportedPackedMaterialDatas - }.Run(); + GPUResidentDrawerBurst.ClassifyMaterials(materials, m_Batcher.instanceCullingBatcher.batchMaterialHash.AsReadOnly(), + ref supportedMaterials, ref unsupportedMaterials, ref supportedPackedMaterialDatas); } } @@ -844,13 +838,8 @@ namespace UnityEngine.Rendering if (unsupportedMaterials.Length > 0) { - new FindUnsupportedRenderersJob - { - unsupportedMaterials = unsupportedMaterials.AsReadOnly(), - materialIDArrays = m_BatchersContext.sharedInstanceData.materialIDArrays, - rendererGroups = m_BatchersContext.sharedInstanceData.rendererGroupIDs, - unsupportedRenderers = unsupportedRenderers, - }.Run(); + GPUResidentDrawerBurst.FindUnsupportedRenderers(unsupportedMaterials, m_BatchersContext.sharedInstanceData.materialIDArrays, + m_BatchersContext.sharedInstanceData.rendererGroupIDs, ref unsupportedRenderers); } return unsupportedRenderers; @@ -860,13 +849,8 @@ namespace UnityEngine.Rendering { NativeHashSet filteredMaterials = new NativeHashSet(materials.Length, allocator); - new GetMaterialsWithChangedPackedMaterialJob - { - materialIDs = materials.AsReadOnly(), - packedMaterialDatas = packedMaterialDatas.AsReadOnly(), - packedMaterialHash = batcher.instanceCullingBatcher.packedMaterialHash.AsReadOnly(), - filteredMaterials = filteredMaterials - }.Run(); + GPUResidentDrawerBurst.GetMaterialsWithChangedPackedMaterial(materials, packedMaterialDatas, + batcher.instanceCullingBatcher.packedMaterialHash.AsReadOnly(), ref filteredMaterials); return filteredMaterials; } @@ -893,79 +877,6 @@ namespace UnityEngine.Rendering return (renderersWithMaterials, renderersWithMeshes); } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct ClassifyMaterialsJob : IJob - { - [ReadOnly] public NativeParallelHashMap.ReadOnly batchMaterialHash; - [ReadOnly] public NativeArray.ReadOnly materialIDs; - - public NativeList supportedMaterialIDs; - public NativeList unsupportedMaterialIDs; - public NativeList supportedPackedMaterialDatas; - - public void Execute() - { - var usedMaterialIDs = new NativeList(4, Allocator.TempJob); - - foreach (var materialID in materialIDs) - { - if (batchMaterialHash.ContainsKey(materialID)) - usedMaterialIDs.Add(materialID); - } - - if (usedMaterialIDs.IsEmpty) - { - usedMaterialIDs.Dispose(); - return; - } - - unsupportedMaterialIDs.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); - supportedMaterialIDs.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); - supportedPackedMaterialDatas.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); - - int unsupportedMaterialCount = GPUDrivenProcessor.ClassifyMaterials(usedMaterialIDs.AsArray(), unsupportedMaterialIDs.AsArray(), supportedMaterialIDs.AsArray(), supportedPackedMaterialDatas.AsArray()); - - unsupportedMaterialIDs.Resize(unsupportedMaterialCount, NativeArrayOptions.ClearMemory); - supportedMaterialIDs.Resize(usedMaterialIDs.Length - unsupportedMaterialCount, NativeArrayOptions.ClearMemory); - supportedPackedMaterialDatas.Resize(supportedMaterialIDs.Length, NativeArrayOptions.ClearMemory); - - usedMaterialIDs.Dispose(); - } - } - - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct FindUnsupportedRenderersJob : IJob - { - [ReadOnly] public NativeArray.ReadOnly unsupportedMaterials; - [ReadOnly] public NativeArray.ReadOnly materialIDArrays; - [ReadOnly] public NativeArray.ReadOnly rendererGroups; - - public NativeList unsupportedRenderers; - - public unsafe void Execute() - { - if (unsupportedMaterials.Length == 0) - return; - - for (int arrayIndex = 0; arrayIndex < materialIDArrays.Length; arrayIndex++) - { - var materialIDs = materialIDArrays[arrayIndex]; - int rendererID = rendererGroups[arrayIndex]; - - for (int i = 0; i < materialIDs.Length; i++) - { - int materialID = materialIDs[i]; - - if (unsupportedMaterials.Contains(materialID)) - { - unsupportedRenderers.Add(rendererID); - break; - } - } - } - } - } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] private unsafe struct FindRenderersFromMaterialOrMeshJob : IJobParallelForBatch { @@ -1012,7 +923,7 @@ namespace UnityEngine.Rendering } { var rendererMaterials = materialIDArrays[rendererIndex]; - + for (int materialIndex = 0; materialIndex < rendererMaterials.Length; materialIndex++) { var materialID = rendererMaterials[materialIndex]; @@ -1029,30 +940,5 @@ namespace UnityEngine.Rendering selectedRenderGroupsForMeshes.AddRangeNoResize(renderersToAddForMeshesPtr, renderersToAddForMeshes.Length); } } - - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct GetMaterialsWithChangedPackedMaterialJob : IJob - { - [ReadOnly] public NativeArray.ReadOnly materialIDs; - [ReadOnly] public NativeArray.ReadOnly packedMaterialDatas; - [ReadOnly] public NativeParallelHashMap.ReadOnly packedMaterialHash; - - [WriteOnly] public NativeHashSet filteredMaterials; - - public void Execute() - { - for (int index = 0; index < materialIDs.Length ; index++) - { - var materialID = materialIDs[index]; - var newPackedMaterialData = packedMaterialDatas[index]; - - // Has its packed material changed? If the material isn't in the packed material cache, consider the material has changed. - if (packedMaterialHash.TryGetValue(materialID, out var packedMaterial) && packedMaterial.Equals(newPackedMaterialData)) - continue; - - filteredMaterials.Add(materialID); - } - } - } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs new file mode 100644 index 00000000..ddb0db8c --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs @@ -0,0 +1,80 @@ +using Unity.Collections; +using UnityEngine.Rendering; +using Unity.Burst; + +namespace UnityEngine.Rendering +{ + [BurstCompile] + internal static class GPUResidentDrawerBurst + { + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void ClassifyMaterials(in NativeArray materialIDs, in NativeParallelHashMap.ReadOnly batchMaterialHash, + ref NativeList supportedMaterialIDs, ref NativeList unsupportedMaterialIDs, ref NativeList supportedPackedMaterialDatas) + { + var usedMaterialIDs = new NativeList(4, Allocator.Temp); + + foreach (var materialID in materialIDs) + { + if (batchMaterialHash.ContainsKey(materialID)) + usedMaterialIDs.Add(materialID); + } + + if (usedMaterialIDs.IsEmpty) + { + usedMaterialIDs.Dispose(); + return; + } + + unsupportedMaterialIDs.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); + supportedMaterialIDs.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); + supportedPackedMaterialDatas.Resize(usedMaterialIDs.Length, NativeArrayOptions.UninitializedMemory); + + int unsupportedMaterialCount = GPUDrivenProcessor.ClassifyMaterials(usedMaterialIDs.AsArray(), unsupportedMaterialIDs.AsArray(), supportedMaterialIDs.AsArray(), supportedPackedMaterialDatas.AsArray()); + + unsupportedMaterialIDs.Resize(unsupportedMaterialCount, NativeArrayOptions.ClearMemory); + supportedMaterialIDs.Resize(usedMaterialIDs.Length - unsupportedMaterialCount, NativeArrayOptions.ClearMemory); + supportedPackedMaterialDatas.Resize(supportedMaterialIDs.Length, NativeArrayOptions.ClearMemory); + + usedMaterialIDs.Dispose(); + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void FindUnsupportedRenderers(in NativeArray unsupportedMaterials, in NativeArray.ReadOnly materialIDArrays, in NativeArray.ReadOnly rendererGroups, + ref NativeList unsupportedRenderers) + { + for (int arrayIndex = 0; arrayIndex < materialIDArrays.Length; arrayIndex++) + { + var materialIDs = materialIDArrays[arrayIndex]; + int rendererID = rendererGroups[arrayIndex]; + + for (int i = 0; i < materialIDs.Length; i++) + { + int materialID = materialIDs[i]; + + if (unsupportedMaterials.Contains(materialID)) + { + unsupportedRenderers.Add(rendererID); + break; + } + } + } + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void GetMaterialsWithChangedPackedMaterial(in NativeArray materialIDs, in NativeArray packedMaterialDatas, + in NativeParallelHashMap.ReadOnly packedMaterialHash, ref NativeHashSet filteredMaterials) + { + for (int index = 0; index < materialIDs.Length ; index++) + { + var materialID = materialIDs[index]; + var newPackedMaterialData = packedMaterialDatas[index]; + + // Has its packed material changed? If the material isn't in the packed material cache, consider the material has changed. + if (packedMaterialHash.TryGetValue(materialID, out var packedMaterial) && packedMaterial.Equals(newPackedMaterialData)) + continue; + + filteredMaterials.Add(materialID); + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs.meta new file mode 100644 index 00000000..ececc7dd --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerBurst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2f50a3b1f0997d342837e27ab3b95e6f \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerDebug.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerDebug.cs index 15d05fb0..36102b9a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerDebug.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawerDebug.cs @@ -10,7 +10,10 @@ namespace UnityEngine.Rendering public BatchCullingViewType viewType; public int viewInstanceID; public int splitIndex; - public int visibleInstances; + public int visibleInstancesOnCPU; + public int visibleInstancesOnGPU; + public int visiblePrimitivesOnCPU; + public int visiblePrimitivesOnGPU; public int drawCommands; } @@ -29,6 +32,8 @@ namespace UnityEngine.Rendering public OcclusionTest occlusionTest; public int visibleInstances; public int culledInstances; + public int visiblePrimitives; + public int culledPrimitives; } internal struct DebugOccluderStats @@ -55,6 +60,48 @@ namespace UnityEngine.Rendering occluderStats = new NativeList(Allocator.Persistent); } + public void FinalizeInstanceCullerViewStats() + { + // For each view, update the on GPU instance and primitive counts. The final rendered primitive and + // instance count can be found at the last pass of all the occlusion passes. + for (int viewIndex = 0; viewIndex < instanceCullerStats.Length; viewIndex++) + { + InstanceCullerViewStats cullerStats = instanceCullerStats[viewIndex]; + InstanceOcclusionEventStats lastOcclusionEventStats = GetLastInstanceOcclusionEventStatsForView(viewIndex); + + if (lastOcclusionEventStats.viewInstanceID == cullerStats.viewInstanceID) + { + // The Min test is because the SelectionOutline view (and probably picking as well) share the same viewInstanceID with + // the scene camera for instance, so we pick up the camera's occlusion event. And we can't have more instances on GPU than we had on CPU. + cullerStats.visibleInstancesOnGPU = Math.Min(lastOcclusionEventStats.visibleInstances, cullerStats.visibleInstancesOnCPU); + cullerStats.visiblePrimitivesOnGPU = Math.Min(lastOcclusionEventStats.visiblePrimitives, cullerStats.visiblePrimitivesOnCPU); + } + else + { + // There was no occlusion culling for this view, so reuse the same counts as on the CPU. + cullerStats.visibleInstancesOnGPU = cullerStats.visibleInstancesOnCPU; + cullerStats.visiblePrimitivesOnGPU = cullerStats.visiblePrimitivesOnCPU; + } + + instanceCullerStats[viewIndex] = cullerStats; + } + } + + private InstanceOcclusionEventStats GetLastInstanceOcclusionEventStatsForView(int viewIndex) + { + if (viewIndex < instanceCullerStats.Length) + { + int viewInstanceID = instanceCullerStats[viewIndex].viewInstanceID; + for (int passIndex = instanceOcclusionEventStats.Length - 1; passIndex >= 0; passIndex--) + { + if (instanceOcclusionEventStats[passIndex].viewInstanceID == viewInstanceID) + return instanceOcclusionEventStats[passIndex]; + } + } + + return new InstanceOcclusionEventStats(); + } + public void Dispose() { if (instanceCullerStats.IsCreated) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs index a980a3e2..1c206649 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs @@ -429,7 +429,21 @@ namespace UnityEngine.Rendering return instanceData.localToWorldIsFlippedBits.Get(instanceIndex); } - unsafe public void Execute(int batchIndex) + + static int GetPrimitiveCount(int indexCount, MeshTopology topology, bool nativeQuads) + { + switch (topology) + { + case MeshTopology.Triangles: return indexCount / 3; + case MeshTopology.Quads: return nativeQuads ? (indexCount / 4) : (indexCount / 4 * 2); + case MeshTopology.Lines: return indexCount / 2; + case MeshTopology.LineStrip: return (indexCount >= 1) ? (indexCount - 1) : 0; + case MeshTopology.Points: return indexCount; + default: Debug.Assert(false, "unknown primitive type"); return 0; + } + } + + public void Execute(int batchIndex) { // figure out how many combinations of views/features we need to partition by int configCount = binningConfig.visibilityConfigCount; @@ -529,7 +543,12 @@ namespace UnityEngine.Rendering int visibleCount = visibleCountPerView[viewIndex]; if (visibleCount > 0) + { + int primitiveCount = GetPrimitiveCount((int)drawBatch.procInfo.indexCount, drawBatch.procInfo.topology, false); + Interlocked.Add(ref UnsafeUtility.AsRef(counterPtr + (int)InstanceCullerSplitDebugCounter.VisibleInstances), visibleCount); + Interlocked.Add(ref UnsafeUtility.AsRef(counterPtr + (int)InstanceCullerSplitDebugCounter.VisiblePrimitives), visibleCount * primitiveCount); + } } } } @@ -854,7 +873,7 @@ namespace UnityEngine.Rendering firstIndex = drawBatch.procInfo.firstIndex, baseVertex = drawBatch.procInfo.baseVertex, firstInstanceGlobalIndex = (uint)instanceInfoGlobalIndex, - maxInstanceCount = (uint)visibleInstanceCount, + maxInstanceCountAndTopology = ((uint)visibleInstanceCount << 3) | (uint)drawBatch.procInfo.topology, }; output.indirectDrawCommands[drawCommandOffset] = new BatchDrawCommandIndirect { @@ -1215,6 +1234,7 @@ namespace UnityEngine.Rendering internal enum InstanceCullerSplitDebugCounter { VisibleInstances, + VisiblePrimitives, DrawCommands, Count, } @@ -1293,7 +1313,10 @@ namespace UnityEngine.Rendering viewType = info.viewType, viewInstanceID = info.viewInstanceID, splitIndex = info.splitIndex, - visibleInstances = m_Counters[counterBase + (int)InstanceCullerSplitDebugCounter.VisibleInstances], + visibleInstancesOnCPU = m_Counters[counterBase + (int)InstanceCullerSplitDebugCounter.VisibleInstances], + visibleInstancesOnGPU = 0, // Unknown at this point, will be filled in later + visiblePrimitivesOnCPU = m_Counters[counterBase + (int)InstanceCullerSplitDebugCounter.VisiblePrimitives], + visiblePrimitivesOnGPU = 0, // Unknown at this point, will be filled in later drawCommands = m_Counters[counterBase + (int)InstanceCullerSplitDebugCounter.DrawCommands], }); } @@ -1442,8 +1465,10 @@ namespace UnityEngine.Rendering } int counterBase = index * (int)InstanceOcclusionTestDebugCounter.Count; - int occludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.Occluded]; - int notOccludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.NotOccluded]; + int instancesOccludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.InstancesOccluded]; + int instancesNotOccludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.InstancesNotOccluded]; + int primitivesOccludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.PrimitivesOccluded]; + int primitivesNotOccludedCounter = m_LatestCounters[counterBase + (int)InstanceOcclusionTestDebugCounter.PrimitivesNotOccluded]; debugStats.instanceOcclusionEventStats.Add(new InstanceOcclusionEventStats { @@ -1452,8 +1477,10 @@ namespace UnityEngine.Rendering occluderVersion = occluderVersion, subviewMask = info.subviewMask, occlusionTest = info.occlusionTest, - visibleInstances = notOccludedCounter, - culledInstances = occludedCounter, + visibleInstances = instancesNotOccludedCounter, + culledInstances = instancesOccludedCounter, + visiblePrimitives = primitivesNotOccludedCounter, + culledPrimitives = primitivesOccludedCounter, }); } } @@ -1531,25 +1558,6 @@ namespace UnityEngine.Rendering m_CommandBuffer.name = "EnsureValidOcclusionTestResults"; } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private unsafe struct SetupCullingJobInput : IJob - { - public float lodBias; - [NativeDisableUnsafePtrRestriction] public BatchCullingContext* context; - [NativeDisableUnsafePtrRestriction] public ReceiverPlanes* receiverPlanes; - [NativeDisableUnsafePtrRestriction] public ReceiverSphereCuller* receiverSphereCuller; - [NativeDisableUnsafePtrRestriction] public FrustumPlaneCuller* frustumPlaneCuller; - [NativeDisableUnsafePtrRestriction] public float* screenRelativeMetric; - - public void Execute() - { - *receiverPlanes = ReceiverPlanes.Create(*context, Allocator.TempJob); - *receiverSphereCuller = ReceiverSphereCuller.Create(*context, Allocator.TempJob); - *frustumPlaneCuller = FrustumPlaneCuller.Create(*context, receiverPlanes->planes.AsArray(), *receiverSphereCuller, Allocator.TempJob); - *screenRelativeMetric = LODGroupRenderingUtils.CalculateScreenRelativeMetric(context->lodParameters, lodBias); - } - } - private unsafe JobHandle CreateFrustumCullingJob( in BatchCullingContext cc, in CPUInstanceData.ReadOnly instanceData, @@ -1561,7 +1569,7 @@ namespace UnityEngine.Rendering NativeArray rendererVisibilityMasks, NativeArray rendererCrossFadeValues) { - Assert.IsTrue(cc.cullingSplits.Length <= 6, "InstanceCullingBatcher supports up to 6 culling splits."); + Assert.IsTrue(cc.cullingSplits.Length <= 6, "InstanceCuller supports up to 6 culling splits."); ReceiverPlanes receiverPlanes; ReceiverSphereCuller receiverSphereCuller; @@ -1570,16 +1578,8 @@ namespace UnityEngine.Rendering fixed (BatchCullingContext* contextPtr = &cc) { - new SetupCullingJobInput() - { - lodBias = QualitySettings.lodBias, - context = contextPtr, - frustumPlaneCuller = &frustumPlaneCuller, - receiverPlanes = &receiverPlanes, - receiverSphereCuller = &receiverSphereCuller, - screenRelativeMetric = &screenRelativeMetric, - - }.Run(); + InstanceCullerBurst.SetupCullingJobInput(QualitySettings.lodBias, contextPtr, &receiverPlanes, &receiverSphereCuller, + &frustumPlaneCuller, &screenRelativeMetric); } if (occlusionCullingCommon != null) @@ -2296,6 +2296,7 @@ namespace UnityEngine.Rendering { m_SplitDebugArray.MoveToDebugStatsAndClear(m_DebugStats); m_OcclusionEventDebugArray.MoveToDebugStatsAndClear(m_DebugStats); + m_DebugStats.FinalizeInstanceCullerViewStats(); } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs new file mode 100644 index 00000000..d123762d --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs @@ -0,0 +1,19 @@ +using Unity.Collections; +using Unity.Burst; + +namespace UnityEngine.Rendering +{ + [BurstCompile] + internal static class InstanceCullerBurst + { + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static unsafe void SetupCullingJobInput(float lodBias, BatchCullingContext* context, ReceiverPlanes* receiverPlanes, + ReceiverSphereCuller* receiverSphereCuller, FrustumPlaneCuller* frustumPlaneCuller, float* screenRelativeMetric) + { + *receiverPlanes = ReceiverPlanes.Create(*context, Allocator.TempJob); + *receiverSphereCuller = ReceiverSphereCuller.Create(*context, Allocator.TempJob); + *frustumPlaneCuller = FrustumPlaneCuller.Create(*context, receiverPlanes->planes.AsArray(), *receiverSphereCuller, Allocator.TempJob); + *screenRelativeMetric = LODGroupRenderingUtils.CalculateScreenRelativeMetric(context->lodParameters, lodBias); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs.meta new file mode 100644 index 00000000..dc1b8acb --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 99f3de5decfa27b47a4ab725fc059f50 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs index 75378aee..c2b526d2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs @@ -384,245 +384,6 @@ namespace UnityEngine.Rendering } } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - internal struct CreateDrawBatchesJob : IJob - { - [ReadOnly] public bool implicitInstanceIndices; - [ReadOnly] public NativeArray instances; - [ReadOnly] public GPUDrivenRendererGroupData rendererData; - [ReadOnly] public NativeParallelHashMap.ReadOnly batchMeshHash; - [ReadOnly] public NativeParallelHashMap.ReadOnly batchMaterialHash; - [ReadOnly] public NativeParallelHashMap.ReadOnly packedMaterialDataHash; - - public NativeParallelHashMap rangeHash; - public NativeList drawRanges; - public NativeParallelHashMap batchHash; - public NativeList drawBatches; - - [WriteOnly] public NativeList drawInstances; - - private ref DrawRange EditDrawRange(in RangeKey key) - { - int drawRangeIndex; - - if (!rangeHash.TryGetValue(key, out drawRangeIndex)) - { - var drawRange = new DrawRange { key = key, drawCount = 0, drawOffset = 0 }; - drawRangeIndex = drawRanges.Length; - rangeHash.Add(key, drawRangeIndex); - drawRanges.Add(drawRange); - } - - ref DrawRange data = ref drawRanges.ElementAt(drawRangeIndex); - Assert.IsTrue(data.key.Equals(key)); - - return ref data; - } - - private ref DrawBatch EditDrawBatch(in DrawKey key, in SubMeshDescriptor subMeshDescriptor) - { - var procInfo = new MeshProceduralInfo(); - procInfo.topology = subMeshDescriptor.topology; - procInfo.baseVertex = (uint)subMeshDescriptor.baseVertex; - procInfo.firstIndex = (uint)subMeshDescriptor.indexStart; - procInfo.indexCount = (uint)subMeshDescriptor.indexCount; - - int drawBatchIndex; - - if (!batchHash.TryGetValue(key, out drawBatchIndex)) - { - var drawBatch = new DrawBatch() { key = key, instanceCount = 0, instanceOffset = 0, procInfo = procInfo }; - drawBatchIndex = drawBatches.Length; - batchHash.Add(key, drawBatchIndex); - drawBatches.Add(drawBatch); - } - - ref DrawBatch data = ref drawBatches.ElementAt(drawBatchIndex); - Assert.IsTrue(data.key.Equals(key)); - - return ref data; - } - - public void ProcessRenderer(int i) - { - var meshIndex = rendererData.meshIndex[i]; - var meshID = rendererData.meshID[meshIndex]; - var submeshCount = rendererData.subMeshCount[meshIndex]; - var subMeshDescOffset = rendererData.subMeshDescOffset[meshIndex]; - var batchMeshID = batchMeshHash[meshID]; - var rendererGroupID = rendererData.rendererGroupID[i]; - var startSubMesh = rendererData.subMeshStartIndex[i]; - var gameObjectLayer = rendererData.gameObjectLayer[i]; - var renderingLayerMask = rendererData.renderingLayerMask[i]; - var materialsOffset = rendererData.materialsOffset[i]; - var materialsCount = rendererData.materialsCount[i]; - var lightmapIndex = rendererData.lightmapIndex[i]; - var packedRendererData = rendererData.packedRendererData[i]; - var rendererPriority = rendererData.rendererPriority[i]; - - int instanceCount; - int instanceOffset; - - if (implicitInstanceIndices) - { - instanceCount = 1; - instanceOffset = i; - } - else - { - instanceCount = rendererData.instancesCount[i]; - instanceOffset = rendererData.instancesOffset[i]; - } - - if (instanceCount == 0) - return; - - const int kLightmapIndexMask = 0xffff; - const int kLightmapIndexInfluenceOnly = 0xfffe; - - var overridenComponents = InstanceComponentGroup.Default; - - // Add per-instance wind parameters - if(packedRendererData.hasTree) - overridenComponents |= InstanceComponentGroup.Wind; - - var lmIndexMasked = lightmapIndex & kLightmapIndexMask; - - // Object doesn't have a valid lightmap Index, -> uses probes for lighting - if (lmIndexMasked >= kLightmapIndexInfluenceOnly) - { - // Only add the component when needed to store blended results (shader will use the ambient probe when not present) - if (packedRendererData.lightProbeUsage == LightProbeUsage.BlendProbes) - overridenComponents |= InstanceComponentGroup.LightProbe; - } - else - { - // Add per-instance lightmap parameters - overridenComponents |= InstanceComponentGroup.Lightmap; - } - - // Scan all materials once to retrieve whether this renderer is indirect-compatible or not (and store it in the RangeKey). - Span packedMaterialDatas = stackalloc GPUDrivenPackedMaterialData[materialsCount]; - - var supportsIndirect = true; - for (int matIndex = 0; matIndex < materialsCount; ++matIndex) - { - if (matIndex >= submeshCount) - { - Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted."); - continue; - } - - var materialIndex = rendererData.materialIndex[materialsOffset + matIndex]; - GPUDrivenPackedMaterialData packedMaterialData; - - if (rendererData.packedMaterialData.Length > 0) - { - packedMaterialData = rendererData.packedMaterialData[materialIndex]; - } - else - { - var materialID = rendererData.materialID[materialIndex]; - bool isFound = packedMaterialDataHash.TryGetValue(materialID, out packedMaterialData); - Assert.IsTrue(isFound, "Packed material data not found."); - } - supportsIndirect &= packedMaterialData.isIndirectSupported; - - packedMaterialDatas[matIndex] = packedMaterialData; - } - - var rangeKey = new RangeKey - { - layer = (byte)gameObjectLayer, - renderingLayerMask = renderingLayerMask, - motionMode = packedRendererData.motionVecGenMode, - shadowCastingMode = packedRendererData.shadowCastingMode, - staticShadowCaster = packedRendererData.staticShadowCaster, - rendererPriority = rendererPriority, - supportsIndirect = supportsIndirect - }; - - ref DrawRange drawRange = ref EditDrawRange(rangeKey); - - for (int matIndex = 0; matIndex < materialsCount; ++matIndex) - { - if (matIndex >= submeshCount) - { - Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted."); - continue; - } - - var materialIndex = rendererData.materialIndex[materialsOffset + matIndex]; - var materialID = rendererData.materialID[materialIndex]; - var packedMaterialData = packedMaterialDatas[matIndex]; - - if (materialID == 0) - { - Debug.LogWarning("Material in the shared materials list is null. Object will be partially rendered."); - continue; - } - - batchMaterialHash.TryGetValue(materialID, out BatchMaterialID batchMaterialID); - - // We always provide crossfade value packed in instance index. We don't use None even if there is no LOD to not split the batch. - var flags = BatchDrawCommandFlags.LODCrossFadeValuePacked; - - // Let the engine know if we've opted out of lightmap texture arrays - flags |= BatchDrawCommandFlags.UseLegacyLightmapsKeyword; - - // assume that a custom motion vectors pass contains deformation motion, so should always output motion vectors - // (otherwise this flag is set dynamically during culling only when the transform is changing) - if (packedMaterialData.isMotionVectorsPassEnabled) - flags |= BatchDrawCommandFlags.HasMotion; - - if (packedMaterialData.isTransparent) - flags |= BatchDrawCommandFlags.HasSortingPosition; - - { - var submeshIndex = startSubMesh + matIndex; - var subMeshDesc = rendererData.subMeshDesc[subMeshDescOffset + submeshIndex]; - - var drawKey = new DrawKey - { - materialID = batchMaterialID, - meshID = batchMeshID, - submeshIndex = submeshIndex, - flags = flags, - transparentInstanceId = packedMaterialData.isTransparent ? rendererGroupID : 0, - range = rangeKey, - overridenComponents = (uint)overridenComponents, - // When we've opted out of lightmap texture arrays, we - // need to pass in a valid lightmap index. The engine - // uses this index for sorting and for breaking the - // batch when lightmaps change across draw calls, and - // for binding the correct light map. - lightmapIndex = lightmapIndex - }; - - ref DrawBatch drawBatch = ref EditDrawBatch(drawKey, subMeshDesc); - - if (drawBatch.instanceCount == 0) - ++drawRange.drawCount; - - drawBatch.instanceCount += instanceCount; - - for (int j = 0; j < instanceCount; ++j) - { - var instanceIndex = instanceOffset + j; - InstanceHandle instance = instances[instanceIndex]; - drawInstances.Add(new DrawInstance { key = drawKey, instanceIndex = instance.index }); - } - } - } - } - - public void Execute() - { - for (int i = 0; i < rendererData.rendererGroupID.Length; ++i) - ProcessRenderer(i); - } - } - internal class CPUDrawInstanceData { public NativeList drawInstances => m_DrawInstances; @@ -720,23 +481,16 @@ namespace UnityEngine.Rendering internalDrawIndex.Dispose(); } - public unsafe void DestroyDrawInstanceIndices(NativeArray drawInstanceIndicesToDestroy) + public void DestroyDrawInstanceIndices(NativeArray drawInstanceIndicesToDestroy) { Profiler.BeginSample("DestroyDrawInstanceIndices.ParallelSort"); drawInstanceIndicesToDestroy.ParallelSort().Complete(); Profiler.EndSample(); - var removeDrawInstanceIndicesJob = new RemoveDrawInstanceIndicesJob - { - drawInstanceIndices = drawInstanceIndicesToDestroy, - drawInstances = m_DrawInstances, - drawBatches = m_DrawBatches, - drawRanges = m_DrawRanges, - batchHash = m_BatchHash, - rangeHash = m_RangeHash - }; - - removeDrawInstanceIndicesJob.Run(); + Profiler.BeginSample("DestroyDrawInstanceIndices.RemoveDrawInstanceIndices"); + InstanceCullingBatcherBurst.RemoveDrawInstanceIndices(drawInstanceIndicesToDestroy, ref m_DrawInstances, ref m_RangeHash, + ref m_BatchHash, ref m_DrawRanges, ref m_DrawBatches); + Profiler.EndSample(); } public unsafe void DestroyDrawInstances(NativeArray destroyedInstances) @@ -1150,20 +904,14 @@ namespace UnityEngine.Rendering RegisterBatchMeshes(rendererData.meshID); } - new CreateDrawBatchesJob - { - implicitInstanceIndices = rendererData.instancesCount.Length == 0, - instances = instances, - rendererData = rendererData, - batchMeshHash = m_BatchMeshHash.AsReadOnly(), - batchMaterialHash = m_BatchMaterialHash.AsReadOnly(), - packedMaterialDataHash = m_PackedMaterialHash.AsReadOnly(), - rangeHash = m_DrawInstanceData.rangeHash, - drawRanges = m_DrawInstanceData.drawRanges, - batchHash = m_DrawInstanceData.batchHash, - drawBatches = m_DrawInstanceData.drawBatches, - drawInstances = m_DrawInstanceData.drawInstances - }.Run(); + var rangeHash = m_DrawInstanceData.rangeHash; + var drawRanges = m_DrawInstanceData.drawRanges; + var batchHash = m_DrawInstanceData.batchHash; + var drawBatches = m_DrawInstanceData.drawBatches; + var drawInstances = m_DrawInstanceData.drawInstances; + + InstanceCullingBatcherBurst.CreateDrawBatches(rendererData.instancesCount.Length == 0, instances, rendererData, + m_BatchMeshHash, m_BatchMaterialHash, m_PackedMaterialHash, ref rangeHash, ref drawRanges, ref batchHash, ref drawBatches, ref drawInstances); m_DrawInstanceData.NeedsRebuild(); UpdateInstanceDataBufferLayoutVersion(); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs new file mode 100644 index 00000000..b3e353d6 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs @@ -0,0 +1,301 @@ +using System; +using Unity.Collections; +using Unity.Burst; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine.Assertions; + +namespace UnityEngine.Rendering +{ + [BurstCompile] + internal static class InstanceCullingBatcherBurst + { + private static void RemoveDrawRange(in RangeKey key, ref NativeParallelHashMap rangeHash, ref NativeList drawRanges) + { + int drawRangeIndex = rangeHash[key]; + + ref DrawRange lastDrawRange = ref drawRanges.ElementAt(drawRanges.Length - 1); + rangeHash[lastDrawRange.key] = drawRangeIndex; + + rangeHash.Remove(key); + drawRanges.RemoveAtSwapBack(drawRangeIndex); + } + + private static void RemoveDrawBatch(in DrawKey key, ref NativeList drawRanges, ref NativeParallelHashMap rangeHash, + ref NativeParallelHashMap batchHash, ref NativeList drawBatches) + { + int drawBatchIndex = batchHash[key]; + + int drawRangeIndex = rangeHash[key.range]; + ref DrawRange drawRange = ref drawRanges.ElementAt(drawRangeIndex); + + Assert.IsTrue(drawRange.drawCount > 0); + + if (--drawRange.drawCount == 0) + RemoveDrawRange(drawRange.key, ref rangeHash, ref drawRanges); + + ref DrawBatch lastDrawBatch = ref drawBatches.ElementAt(drawBatches.Length - 1); + batchHash[lastDrawBatch.key] = drawBatchIndex; + + batchHash.Remove(key); + drawBatches.RemoveAtSwapBack(drawBatchIndex); + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static unsafe void RemoveDrawInstanceIndices(in NativeArray drawInstanceIndices, ref NativeList drawInstances, ref NativeParallelHashMap rangeHash, + ref NativeParallelHashMap batchHash, ref NativeList drawRanges, ref NativeList drawBatches) + { + var drawInstancesPtr = (DrawInstance*)drawInstances.GetUnsafePtr(); + var drawInstancesNewBack = drawInstances.Length - 1; + + for (int indexRev = drawInstanceIndices.Length - 1; indexRev >= 0; --indexRev) + { + int indexToRemove = drawInstanceIndices[indexRev]; + DrawInstance* drawInstance = drawInstancesPtr + indexToRemove; + + int drawBatchIndex = batchHash[drawInstance->key]; + ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex); + + Assert.IsTrue(drawBatch.instanceCount > 0); + + if (--drawBatch.instanceCount == 0) + RemoveDrawBatch(drawBatch.key, ref drawRanges, ref rangeHash, ref batchHash, ref drawBatches); + + UnsafeUtility.MemCpy(drawInstance, drawInstancesPtr + drawInstancesNewBack--, sizeof(DrawInstance)); + } + + drawInstances.ResizeUninitialized(drawInstancesNewBack + 1); + } + + private static ref DrawRange EditDrawRange(in RangeKey key, NativeParallelHashMap rangeHash, NativeList drawRanges) + { + int drawRangeIndex; + + if (!rangeHash.TryGetValue(key, out drawRangeIndex)) + { + var drawRange = new DrawRange { key = key, drawCount = 0, drawOffset = 0 }; + drawRangeIndex = drawRanges.Length; + rangeHash.Add(key, drawRangeIndex); + drawRanges.Add(drawRange); + } + + ref DrawRange data = ref drawRanges.ElementAt(drawRangeIndex); + Assert.IsTrue(data.key.Equals(key)); + + return ref data; + } + + private static ref DrawBatch EditDrawBatch(in DrawKey key, in SubMeshDescriptor subMeshDescriptor, NativeParallelHashMap batchHash, NativeList drawBatches) + { + var procInfo = new MeshProceduralInfo(); + procInfo.topology = subMeshDescriptor.topology; + procInfo.baseVertex = (uint)subMeshDescriptor.baseVertex; + procInfo.firstIndex = (uint)subMeshDescriptor.indexStart; + procInfo.indexCount = (uint)subMeshDescriptor.indexCount; + + int drawBatchIndex; + + if (!batchHash.TryGetValue(key, out drawBatchIndex)) + { + var drawBatch = new DrawBatch() { key = key, instanceCount = 0, instanceOffset = 0, procInfo = procInfo }; + drawBatchIndex = drawBatches.Length; + batchHash.Add(key, drawBatchIndex); + drawBatches.Add(drawBatch); + } + + ref DrawBatch data = ref drawBatches.ElementAt(drawBatchIndex); + Assert.IsTrue(data.key.Equals(key)); + + return ref data; + } + + private static void ProcessRenderer(int i, bool implicitInstanceIndices, in GPUDrivenRendererGroupData rendererData, + NativeParallelHashMap batchMeshHash, NativeParallelHashMap packedMaterialDataHash, + NativeParallelHashMap batchMaterialHash, NativeArray instances, NativeList drawInstances, + NativeParallelHashMap rangeHash, NativeList drawRanges, NativeParallelHashMap batchHash, + NativeList drawBatches) + { + var meshIndex = rendererData.meshIndex[i]; + var meshID = rendererData.meshID[meshIndex]; + var submeshCount = rendererData.subMeshCount[meshIndex]; + var subMeshDescOffset = rendererData.subMeshDescOffset[meshIndex]; + var batchMeshID = batchMeshHash[meshID]; + var rendererGroupID = rendererData.rendererGroupID[i]; + var startSubMesh = rendererData.subMeshStartIndex[i]; + var gameObjectLayer = rendererData.gameObjectLayer[i]; + var renderingLayerMask = rendererData.renderingLayerMask[i]; + var materialsOffset = rendererData.materialsOffset[i]; + var materialsCount = rendererData.materialsCount[i]; + var lightmapIndex = rendererData.lightmapIndex[i]; + var packedRendererData = rendererData.packedRendererData[i]; + var rendererPriority = rendererData.rendererPriority[i]; + + int instanceCount; + int instanceOffset; + + if (implicitInstanceIndices) + { + instanceCount = 1; + instanceOffset = i; + } + else + { + instanceCount = rendererData.instancesCount[i]; + instanceOffset = rendererData.instancesOffset[i]; + } + + if (instanceCount == 0) + return; + + const int kLightmapIndexMask = 0xffff; + const int kLightmapIndexInfluenceOnly = 0xfffe; + + var overridenComponents = InstanceComponentGroup.Default; + + // Add per-instance wind parameters + if(packedRendererData.hasTree) + overridenComponents |= InstanceComponentGroup.Wind; + + var lmIndexMasked = lightmapIndex & kLightmapIndexMask; + + // Object doesn't have a valid lightmap Index, -> uses probes for lighting + if (lmIndexMasked >= kLightmapIndexInfluenceOnly) + { + // Only add the component when needed to store blended results (shader will use the ambient probe when not present) + if (packedRendererData.lightProbeUsage == LightProbeUsage.BlendProbes) + overridenComponents |= InstanceComponentGroup.LightProbe; + } + else + { + // Add per-instance lightmap parameters + overridenComponents |= InstanceComponentGroup.Lightmap; + } + + // Scan all materials once to retrieve whether this renderer is indirect-compatible or not (and store it in the RangeKey). + Span packedMaterialDatas = stackalloc GPUDrivenPackedMaterialData[materialsCount]; + + var supportsIndirect = true; + for (int matIndex = 0; matIndex < materialsCount; ++matIndex) + { + if (matIndex >= submeshCount) + { + Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted."); + continue; + } + + var materialIndex = rendererData.materialIndex[materialsOffset + matIndex]; + GPUDrivenPackedMaterialData packedMaterialData; + + if (rendererData.packedMaterialData.Length > 0) + { + packedMaterialData = rendererData.packedMaterialData[materialIndex]; + } + else + { + var materialID = rendererData.materialID[materialIndex]; + bool isFound = packedMaterialDataHash.TryGetValue(materialID, out packedMaterialData); + Assert.IsTrue(isFound, "Packed material data not found."); + } + supportsIndirect &= packedMaterialData.isIndirectSupported; + + packedMaterialDatas[matIndex] = packedMaterialData; + } + + var rangeKey = new RangeKey + { + layer = (byte)gameObjectLayer, + renderingLayerMask = renderingLayerMask, + motionMode = packedRendererData.motionVecGenMode, + shadowCastingMode = packedRendererData.shadowCastingMode, + staticShadowCaster = packedRendererData.staticShadowCaster, + rendererPriority = rendererPriority, + supportsIndirect = supportsIndirect + }; + + ref DrawRange drawRange = ref EditDrawRange(rangeKey, rangeHash, drawRanges); + + for (int matIndex = 0; matIndex < materialsCount; ++matIndex) + { + if (matIndex >= submeshCount) + { + Debug.LogWarning("Material count in the shared material list is higher than sub mesh count for the mesh. Object may be corrupted."); + continue; + } + + var materialIndex = rendererData.materialIndex[materialsOffset + matIndex]; + var materialID = rendererData.materialID[materialIndex]; + var packedMaterialData = packedMaterialDatas[matIndex]; + + if (materialID == 0) + { + Debug.LogWarning("Material in the shared materials list is null. Object will be partially rendered."); + continue; + } + + batchMaterialHash.TryGetValue(materialID, out BatchMaterialID batchMaterialID); + + // We always provide crossfade value packed in instance index. We don't use None even if there is no LOD to not split the batch. + var flags = BatchDrawCommandFlags.LODCrossFadeValuePacked; + + // Let the engine know if we've opted out of lightmap texture arrays + flags |= BatchDrawCommandFlags.UseLegacyLightmapsKeyword; + + // assume that a custom motion vectors pass contains deformation motion, so should always output motion vectors + // (otherwise this flag is set dynamically during culling only when the transform is changing) + if (packedMaterialData.isMotionVectorsPassEnabled) + flags |= BatchDrawCommandFlags.HasMotion; + + if (packedMaterialData.isTransparent) + flags |= BatchDrawCommandFlags.HasSortingPosition; + + { + var submeshIndex = startSubMesh + matIndex; + var subMeshDesc = rendererData.subMeshDesc[subMeshDescOffset + submeshIndex]; + var drawKey = new DrawKey + { + materialID = batchMaterialID, + meshID = batchMeshID, + submeshIndex = submeshIndex, + flags = flags, + transparentInstanceId = packedMaterialData.isTransparent ? rendererGroupID : 0, + range = rangeKey, + overridenComponents = (uint)overridenComponents, + // When we've opted out of lightmap texture arrays, we + // need to pass in a valid lightmap index. The engine + // uses this index for sorting and for breaking the + // batch when lightmaps change across draw calls, and + // for binding the correct light map. + lightmapIndex = lightmapIndex + }; + + ref DrawBatch drawBatch = ref EditDrawBatch(drawKey, subMeshDesc, batchHash, drawBatches); + + if (drawBatch.instanceCount == 0) + ++drawRange.drawCount; + + drawBatch.instanceCount += instanceCount; + + for (int j = 0; j < instanceCount; ++j) + { + var instanceIndex = instanceOffset + j; + InstanceHandle instance = instances[instanceIndex]; + drawInstances.Add(new DrawInstance { key = drawKey, instanceIndex = instance.index }); + } + } + } + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void CreateDrawBatches(bool implicitInstanceIndices, in NativeArray instances, in GPUDrivenRendererGroupData rendererData, + in NativeParallelHashMap batchMeshHash, in NativeParallelHashMap batchMaterialHash, + in NativeParallelHashMap packedMaterialDataHash, + ref NativeParallelHashMap rangeHash, ref NativeList drawRanges, ref NativeParallelHashMap batchHash, ref NativeList drawBatches, + ref NativeList drawInstances) + { + for (int i = 0; i < rendererData.rendererGroupID.Length; ++i) + ProcessRenderer(i, implicitInstanceIndices, rendererData, batchMeshHash, packedMaterialDataHash, batchMaterialHash, instances, + drawInstances, rangeHash, drawRanges, batchHash, drawBatches); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs.meta new file mode 100644 index 00000000..1b344d83 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 07b72b6a7afa9b448b3103bb66d57ca0 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs index 27c3fd30..5de08a63 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs @@ -482,213 +482,6 @@ namespace UnityEngine.Rendering } } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct ReallocateInstancesJob : IJob - { - [ReadOnly] public bool implicitInstanceIndices; - [ReadOnly] public NativeArray rendererGroupIDs; - [ReadOnly] public NativeArray packedRendererData; - [ReadOnly] public NativeArray instanceOffsets; - [ReadOnly] public NativeArray instanceCounts; - - public InstanceAllocators instanceAllocators; - public CPUInstanceData instanceData; - public CPUSharedInstanceData sharedInstanceData; - public NativeArray instances; - public NativeParallelMultiHashMap rendererGroupInstanceMultiHash; - - public void Execute() - { - for (int i = 0; i < rendererGroupIDs.Length; ++i) - { - var rendererGroupID = rendererGroupIDs[i]; - var hasTree = packedRendererData[i].hasTree; - - int instanceCount; - int instanceOffset; - - if (implicitInstanceIndices) - { - instanceCount = 1; - instanceOffset = i; - } - else - { - instanceCount = instanceCounts[i]; - instanceOffset = instanceOffsets[i]; - } - - SharedInstanceHandle sharedInstance; - - if (rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var instance, out var it)) - { - sharedInstance = instanceData.Get_SharedInstance(instance); - - int currentInstancesCount = sharedInstanceData.Get_RefCount(sharedInstance); - int instancesToFreeCount = currentInstancesCount - instanceCount; - - if (instancesToFreeCount > 0) - { - bool success = true; - int freedInstancesCount = 0; - - for (int j = 0; j < instanceCount; ++j) - success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); - - Assert.IsTrue(success); - - while (success) - { - instanceData.Remove(instance); - instanceAllocators.FreeInstance(instance); - - rendererGroupInstanceMultiHash.Remove(it); - ++freedInstancesCount; - success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); - } - - Assert.AreEqual(instancesToFreeCount, freedInstancesCount); - } - } - else - { - sharedInstance = instanceAllocators.AllocateSharedInstance(); - sharedInstanceData.AddNoGrow(sharedInstance); - } - - if (instanceCount > 0) - { - sharedInstanceData.Set_RefCount(sharedInstance, instanceCount); - - for (int j = 0; j < instanceCount; ++j) - { - int instanceIndex = instanceOffset + j; - - if (instances[instanceIndex].valid) - continue; - - InstanceHandle newInstance; - - if (!hasTree) - newInstance = instanceAllocators.AllocateInstance(InstanceType.MeshRenderer); - else - newInstance = instanceAllocators.AllocateInstance(InstanceType.SpeedTree); - - instanceData.AddNoGrow(newInstance); - int index = instanceData.InstanceToIndex(newInstance); - instanceData.sharedInstances[index] = sharedInstance; - instanceData.movedInCurrentFrameBits.Set(index, false); - instanceData.movedInPreviousFrameBits.Set(index, false); - instanceData.visibleInPreviousFrameBits.Set(index, false); - - rendererGroupInstanceMultiHash.Add(rendererGroupID, newInstance); - instances[instanceIndex] = newInstance; - } - } - else - { - sharedInstanceData.Remove(sharedInstance); - instanceAllocators.FreeSharedInstance(sharedInstance); - } - } - } - } - - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct FreeInstancesJob : IJob - { - [ReadOnly] public NativeArray instances; - - public InstanceAllocators instanceAllocators; - public CPUInstanceData instanceData; - public CPUSharedInstanceData sharedInstanceData; - public NativeParallelMultiHashMap rendererGroupInstanceMultiHash; - - public void Execute() - { - foreach (var instance in instances) - { - if (!instanceData.IsValidInstance(instance)) - continue; - - int instanceIndex = instanceData.InstanceToIndex(instance); - SharedInstanceHandle sharedInstance = instanceData.sharedInstances[instanceIndex]; - int sharedInstanceIndex = sharedInstanceData.SharedInstanceToIndex(sharedInstance); - int refCount = sharedInstanceData.refCounts[sharedInstanceIndex]; - var rendererGroupID = sharedInstanceData.rendererGroupIDs[sharedInstanceIndex]; - - Assert.IsTrue(refCount > 0); - - if (refCount > 1) - { - sharedInstanceData.refCounts[sharedInstanceIndex] = refCount - 1; - } - else - { - sharedInstanceData.Remove(sharedInstance); - instanceAllocators.FreeSharedInstance(sharedInstance); - } - - instanceData.Remove(instance); - instanceAllocators.FreeInstance(instance); - - //@ This will have quadratic cost. Optimize later. - for (bool success = rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var i, out var it); success;) - { - if (instance.Equals(i)) - { - rendererGroupInstanceMultiHash.Remove(it); - break; - } - success = rendererGroupInstanceMultiHash.TryGetNextValue(out i, ref it); - } - } - } - } - - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - private struct FreeRendererGroupInstancesJob : IJob - { - [ReadOnly] public NativeArray rendererGroupsID; - - public InstanceAllocators instanceAllocators; - public CPUInstanceData instanceData; - public CPUSharedInstanceData sharedInstanceData; - public NativeParallelMultiHashMap rendererGroupInstanceMultiHash; - - public void Execute() - { - foreach (var rendererGroupID in rendererGroupsID) - { - for (bool success = rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var instance, out var it); success;) - { - SharedInstanceHandle sharedInstance = instanceData.Get_SharedInstance(instance); - int sharedInstanceIndex = sharedInstanceData.SharedInstanceToIndex(sharedInstance); - int refCount = sharedInstanceData.refCounts[sharedInstanceIndex]; - - Assert.IsTrue(refCount > 0); - - if (refCount > 1) - { - sharedInstanceData.refCounts[sharedInstanceIndex] = refCount - 1; - } - else - { - sharedInstanceData.Remove(sharedInstance); - instanceAllocators.FreeSharedInstance(sharedInstance); - } - - instanceData.Remove(instance); - instanceAllocators.FreeInstance(instance); - - success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); - } - - rendererGroupInstanceMultiHash.Remove(rendererGroupID); - } - } - } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] private unsafe struct UpdateRendererInstancesJob : IJobParallelFor { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs index 9ed79f92..1649aeec 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs @@ -475,24 +475,21 @@ namespace UnityEngine.Rendering m_InstanceData.EnsureFreeInstances(newInstancesCount); m_SharedInstanceData.EnsureFreeInstances(newSharedInstancesCount); - new ReallocateInstancesJob { implicitInstanceIndices = implicitInstanceIndices, rendererGroupInstanceMultiHash = m_RendererGroupInstanceMultiHash, - instanceAllocators = m_InstanceAllocators, sharedInstanceData = m_SharedInstanceData, instanceData = m_InstanceData, - rendererGroupIDs = rendererData.rendererGroupID, packedRendererData = rendererData.packedRendererData, instanceOffsets = rendererData.instancesOffset, - instanceCounts = rendererData.instancesCount, instances = instances }.Run(); + InstanceDataSystemBurst.ReallocateInstances(implicitInstanceIndices, rendererData.rendererGroupID, rendererData.packedRendererData, + rendererData.instancesOffset, rendererData.instancesCount, ref m_InstanceAllocators, ref m_InstanceData, + ref m_SharedInstanceData, ref instances, ref m_RendererGroupInstanceMultiHash); } public void FreeRendererGroupInstances(NativeArray rendererGroupsID) { - new FreeRendererGroupInstancesJob { rendererGroupInstanceMultiHash = m_RendererGroupInstanceMultiHash, - instanceAllocators = m_InstanceAllocators, sharedInstanceData = m_SharedInstanceData, instanceData = m_InstanceData, - rendererGroupsID = rendererGroupsID }.Run(); + InstanceDataSystemBurst.FreeRendererGroupInstances(rendererGroupsID.AsReadOnly(), ref m_InstanceAllocators, ref m_InstanceData, + ref m_SharedInstanceData, ref m_RendererGroupInstanceMultiHash); } public void FreeInstances(NativeArray instances) { - new FreeInstancesJob { rendererGroupInstanceMultiHash = m_RendererGroupInstanceMultiHash, - instanceAllocators = m_InstanceAllocators, sharedInstanceData = m_SharedInstanceData, instanceData = m_InstanceData, - instances = instances }.Run(); + InstanceDataSystemBurst.FreeInstances(instances.AsReadOnly(), ref m_InstanceAllocators, ref m_InstanceData, + ref m_SharedInstanceData, ref m_RendererGroupInstanceMultiHash); } public JobHandle ScheduleUpdateInstanceDataJob(NativeArray instances, in GPUDrivenRendererGroupData rendererData, NativeParallelHashMap lodGroupDataMap) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs new file mode 100644 index 00000000..986472f5 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs @@ -0,0 +1,191 @@ +using Unity.Collections; +using Unity.Burst; +using UnityEngine.Assertions; + +namespace UnityEngine.Rendering +{ + [BurstCompile] + internal static class InstanceDataSystemBurst + { + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void ReallocateInstances(bool implicitInstanceIndices, in NativeArray rendererGroupIDs, in NativeArray packedRendererData, + in NativeArray instanceOffsets, in NativeArray instanceCounts, ref InstanceAllocators instanceAllocators, ref CPUInstanceData instanceData, + ref CPUSharedInstanceData sharedInstanceData, ref NativeArray instances, + ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) + { + for (int i = 0; i < rendererGroupIDs.Length; ++i) + { + var rendererGroupID = rendererGroupIDs[i]; + var hasTree = packedRendererData[i].hasTree; + + int instanceCount; + int instanceOffset; + + if (implicitInstanceIndices) + { + instanceCount = 1; + instanceOffset = i; + } + else + { + instanceCount = instanceCounts[i]; + instanceOffset = instanceOffsets[i]; + } + + SharedInstanceHandle sharedInstance; + + if (rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var instance, out var it)) + { + sharedInstance = instanceData.Get_SharedInstance(instance); + + int currentInstancesCount = sharedInstanceData.Get_RefCount(sharedInstance); + int instancesToFreeCount = currentInstancesCount - instanceCount; + + if (instancesToFreeCount > 0) + { + bool success = true; + int freedInstancesCount = 0; + + for (int j = 0; j < instanceCount; ++j) + success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); + + Assert.IsTrue(success); + + while (success) + { + var idx = instanceData.InstanceToIndex(instance); + instanceData.Remove(instance); + + instanceAllocators.FreeInstance(instance); + + rendererGroupInstanceMultiHash.Remove(it); + ++freedInstancesCount; + success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); + } + + Assert.AreEqual(instancesToFreeCount, freedInstancesCount); + } + } + else + { + sharedInstance = instanceAllocators.AllocateSharedInstance(); + sharedInstanceData.AddNoGrow(sharedInstance); + } + + if (instanceCount > 0) + { + sharedInstanceData.Set_RefCount(sharedInstance, instanceCount); + + for (int j = 0; j < instanceCount; ++j) + { + int instanceIndex = instanceOffset + j; + + if (instances[instanceIndex].valid) + continue; + + InstanceHandle newInstance; + + if (!hasTree) + newInstance = instanceAllocators.AllocateInstance(InstanceType.MeshRenderer); + else + newInstance = instanceAllocators.AllocateInstance(InstanceType.SpeedTree); + + instanceData.AddNoGrow(newInstance); + int index = instanceData.InstanceToIndex(newInstance); + instanceData.sharedInstances[index] = sharedInstance; + instanceData.movedInCurrentFrameBits.Set(index, false); + instanceData.movedInPreviousFrameBits.Set(index, false); + instanceData.visibleInPreviousFrameBits.Set(index, false); + + rendererGroupInstanceMultiHash.Add(rendererGroupID, newInstance); + instances[instanceIndex] = newInstance; + } + } + else + { + sharedInstanceData.Remove(sharedInstance); + instanceAllocators.FreeSharedInstance(sharedInstance); + } + } + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void FreeRendererGroupInstances(in NativeArray.ReadOnly rendererGroupsID, ref InstanceAllocators instanceAllocators, ref CPUInstanceData instanceData, + ref CPUSharedInstanceData sharedInstanceData, ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) + { + foreach (var rendererGroupID in rendererGroupsID) + { + for (bool success = rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var instance, out var it); success;) + { + SharedInstanceHandle sharedInstance = instanceData.Get_SharedInstance(instance); + int sharedInstanceIndex = sharedInstanceData.SharedInstanceToIndex(sharedInstance); + int refCount = sharedInstanceData.refCounts[sharedInstanceIndex]; + + Assert.IsTrue(refCount > 0); + + if (refCount > 1) + { + sharedInstanceData.refCounts[sharedInstanceIndex] = refCount - 1; + } + else + { + sharedInstanceData.Remove(sharedInstance); + instanceAllocators.FreeSharedInstance(sharedInstance); + } + + var idx = instanceData.InstanceToIndex(instance); + instanceData.Remove(instance); + instanceAllocators.FreeInstance(instance); + + success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); + } + + rendererGroupInstanceMultiHash.Remove(rendererGroupID); + } + } + + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static void FreeInstances(in NativeArray.ReadOnly instances, ref InstanceAllocators instanceAllocators, ref CPUInstanceData instanceData, + ref CPUSharedInstanceData sharedInstanceData, ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) + { + foreach (var instance in instances) + { + if (!instanceData.IsValidInstance(instance)) + continue; + + int instanceIndex = instanceData.InstanceToIndex(instance); + SharedInstanceHandle sharedInstance = instanceData.sharedInstances[instanceIndex]; + int sharedInstanceIndex = sharedInstanceData.SharedInstanceToIndex(sharedInstance); + int refCount = sharedInstanceData.refCounts[sharedInstanceIndex]; + var rendererGroupID = sharedInstanceData.rendererGroupIDs[sharedInstanceIndex]; + + Assert.IsTrue(refCount > 0); + + if (refCount > 1) + { + sharedInstanceData.refCounts[sharedInstanceIndex] = refCount - 1; + } + else + { + sharedInstanceData.Remove(sharedInstance); + instanceAllocators.FreeSharedInstance(sharedInstance); + } + + instanceData.Remove(instance); + instanceAllocators.FreeInstance(instance); + + //@ This will have quadratic cost. Optimize later. + for (bool success = rendererGroupInstanceMultiHash.TryGetFirstValue(rendererGroupID, out var i, out var it); success;) + { + if (instance.Equals(i)) + { + rendererGroupInstanceMultiHash.Remove(it); + break; + } + success = rendererGroupInstanceMultiHash.TryGetNextValue(out i, ref it); + } + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs.meta new file mode 100644 index 00000000..8613808f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 302f596d55264be4ba359e52ec407766 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs index 6bc76a17..66adf030 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs @@ -74,8 +74,10 @@ namespace UnityEngine.Rendering [GenerateHLSL(needAccessors = false)] internal enum InstanceOcclusionTestDebugCounter { - Occluded, - NotOccluded, + InstancesOccluded, + InstancesNotOccluded, + PrimitivesOccluded, + PrimitivesNotOccluded, Count, } @@ -93,7 +95,7 @@ namespace UnityEngine.Rendering public uint firstIndex; public uint baseVertex; public uint firstInstanceGlobalIndex; - public uint maxInstanceCount; + public uint maxInstanceCountAndTopology; // [31:3]=max_instance_count, [2:0]=topology } internal struct IndirectBufferAllocInfo @@ -280,7 +282,7 @@ namespace UnityEngine.Rendering occluderDepthPyramid = RTHandles.Alloc( occluderDepthPyramidSize.x, occluderDepthPyramidSize.y, format: GraphicsFormat.R32_SFloat, - dimension: TextureDimension.Tex2D, + dimension: TextureDimension.Tex2D, filterMode: FilterMode.Point, wrapMode: TextureWrapMode.Clamp, enableRandomWrite: true, diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs.hlsl index f9aab8a0..832151f2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceOcclusionCuller.cs.hlsl @@ -7,9 +7,11 @@ // // UnityEngine.Rendering.InstanceOcclusionTestDebugCounter: static fields // -#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_OCCLUDED (0) -#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_NOT_OCCLUDED (1) -#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_COUNT (2) +#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_OCCLUDED (0) +#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_NOT_OCCLUDED (1) +#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_OCCLUDED (2) +#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_NOT_OCCLUDED (3) +#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_COUNT (4) // Generated from UnityEngine.Rendering.IndirectDrawInfo // PackingRules = Exact @@ -19,7 +21,7 @@ struct IndirectDrawInfo uint firstIndex; uint baseVertex; uint firstInstanceGlobalIndex; - uint maxInstanceCount; + uint maxInstanceCountAndTopology; }; // Generated from UnityEngine.Rendering.IndirectInstanceInfo diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs index 42705f50..b9e47a3b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs @@ -86,52 +86,6 @@ namespace UnityEngine.Rendering } } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - internal unsafe struct AllocateOrGetLODGroupDataInstancesJob : IJob - { - [ReadOnly] public NativeArray lodGroupsID; - - public NativeList lodGroupsData; - public NativeList lodGroupCullingData; - public NativeParallelHashMap lodGroupDataHash; - public NativeList freeLODGroupDataHandles; - - [WriteOnly] public NativeArray lodGroupInstances; - - [NativeDisableUnsafePtrRestriction] public int* previousRendererCount; - - public void Execute() - { - int freeHandlesCount = freeLODGroupDataHandles.Length; - int lodDataLength = lodGroupsData.Length; - - for (int i = 0; i < lodGroupsID.Length; ++i) - { - int lodGroupID = lodGroupsID[i]; - - if (!lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance)) - { - if (freeHandlesCount == 0) - lodGroupInstance = new GPUInstanceIndex() { index = lodDataLength++ }; - else - lodGroupInstance = freeLODGroupDataHandles[--freeHandlesCount]; - - lodGroupDataHash.TryAdd(lodGroupID, lodGroupInstance); - } - else - { - *previousRendererCount += lodGroupsData.ElementAt(lodGroupInstance.index).rendererCount; - } - - lodGroupInstances[i] = lodGroupInstance; - } - - freeLODGroupDataHandles.ResizeUninitialized(freeHandlesCount); - lodGroupsData.ResizeUninitialized(lodDataLength); - lodGroupCullingData.ResizeUninitialized(lodDataLength); - } - } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] internal unsafe struct UpdateLODGroupDataJob : IJobParallelFor { @@ -219,38 +173,6 @@ namespace UnityEngine.Rendering } } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - internal unsafe struct FreeLODGroupDataJob : IJob - { - [ReadOnly] public NativeArray destroyedLODGroupsID; - - public NativeList lodGroupsData; - public NativeParallelHashMap lodGroupDataHash; - public NativeList freeLODGroupDataHandles; - - [NativeDisableUnsafePtrRestriction] public int* removedRendererCount; - - public void Execute() - { - foreach (int lodGroupID in destroyedLODGroupsID) - { - if (lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance)) - { - Assert.IsTrue(lodGroupInstance.valid); - - lodGroupDataHash.Remove(lodGroupID); - freeLODGroupDataHandles.Add(lodGroupInstance); - - ref LODGroupData lodGroupData = ref lodGroupsData.ElementAt(lodGroupInstance.index); - Assert.IsTrue(lodGroupData.valid); - - *removedRendererCount += lodGroupData.rendererCount; - lodGroupData.valid = false; - } - } - } - } - internal class LODGroupDataPool : IDisposable { private NativeList m_LODGroupData; @@ -329,18 +251,9 @@ namespace UnityEngine.Rendering var lodGroupInstances = new NativeArray(inputData.lodGroupID.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); - int previousRendererCount = 0; - - new AllocateOrGetLODGroupDataInstancesJob - { - lodGroupsID = inputData.lodGroupID, - lodGroupsData = m_LODGroupData, - lodGroupCullingData = m_LODGroupCullingData, - lodGroupDataHash = m_LODGroupDataHash, - freeLODGroupDataHandles = m_FreeLODGroupDataHandles, - lodGroupInstances = lodGroupInstances, - previousRendererCount = &previousRendererCount - }.Run(); + int previousRendererCount = LODGroupDataPoolBurst.AllocateOrGetLODGroupDataInstances(inputData.lodGroupID, + ref m_LODGroupData, ref m_LODGroupCullingData, + ref m_LODGroupDataHash, ref m_FreeLODGroupDataHandles, ref lodGroupInstances); m_CrossfadedRendererCount -= previousRendererCount; Assert.IsTrue(m_CrossfadedRendererCount >= 0); @@ -367,21 +280,12 @@ namespace UnityEngine.Rendering lodGroupInstances.Dispose(); } - public unsafe void FreeLODGroupData(NativeArray destroyedLODGroupsID) + public void FreeLODGroupData(NativeArray destroyedLODGroupsID) { if (destroyedLODGroupsID.Length == 0) return; - int removedRendererCount = 0; - - new FreeLODGroupDataJob - { - destroyedLODGroupsID = destroyedLODGroupsID, - lodGroupsData = m_LODGroupData, - lodGroupDataHash = m_LODGroupDataHash, - freeLODGroupDataHandles = m_FreeLODGroupDataHandles, - removedRendererCount = &removedRendererCount - }.Run(); + int removedRendererCount = LODGroupDataPoolBurst.FreeLODGroupData(destroyedLODGroupsID, ref m_LODGroupData, ref m_LODGroupDataHash, ref m_FreeLODGroupDataHandles); m_CrossfadedRendererCount -= removedRendererCount; Assert.IsTrue(m_CrossfadedRendererCount >= 0); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs new file mode 100644 index 00000000..efe0342a --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs @@ -0,0 +1,72 @@ +using Unity.Collections; +using Unity.Burst; +using UnityEngine.Assertions; + +namespace UnityEngine.Rendering +{ + [BurstCompile] + internal static class LODGroupDataPoolBurst + { + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static int FreeLODGroupData(in NativeArray destroyedLODGroupsID, ref NativeList lodGroupsData, + ref NativeParallelHashMap lodGroupDataHash, ref NativeList freeLODGroupDataHandles) + { + int removedRendererCount = 0; + + foreach (int lodGroupID in destroyedLODGroupsID) + { + if (lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance)) + { + Assert.IsTrue(lodGroupInstance.valid); + + lodGroupDataHash.Remove(lodGroupID); + freeLODGroupDataHandles.Add(lodGroupInstance); + + ref LODGroupData lodGroupData = ref lodGroupsData.ElementAt(lodGroupInstance.index); + Assert.IsTrue(lodGroupData.valid); + + removedRendererCount += lodGroupData.rendererCount; + lodGroupData.valid = false; + } + } + + return removedRendererCount; + } + + [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + public static int AllocateOrGetLODGroupDataInstances(in NativeArray lodGroupsID, ref NativeList lodGroupsData, ref NativeList lodGroupCullingData, + ref NativeParallelHashMap lodGroupDataHash, ref NativeList freeLODGroupDataHandles, ref NativeArray lodGroupInstances) + { + int freeHandlesCount = freeLODGroupDataHandles.Length; + int lodDataLength = lodGroupsData.Length; + int previousRendererCount = 0; + + for (int i = 0; i < lodGroupsID.Length; ++i) + { + int lodGroupID = lodGroupsID[i]; + + if (!lodGroupDataHash.TryGetValue(lodGroupID, out var lodGroupInstance)) + { + if (freeHandlesCount == 0) + lodGroupInstance = new GPUInstanceIndex() { index = lodDataLength++ }; + else + lodGroupInstance = freeLODGroupDataHandles[--freeHandlesCount]; + + lodGroupDataHash.TryAdd(lodGroupID, lodGroupInstance); + } + else + { + previousRendererCount += lodGroupsData.ElementAt(lodGroupInstance.index).rendererCount; + } + + lodGroupInstances[i] = lodGroupInstance; + } + + freeLODGroupDataHandles.ResizeUninitialized(freeHandlesCount); + lodGroupsData.ResizeUninitialized(lodDataLength); + lodGroupCullingData.ResizeUninitialized(lodDataLength); + + return previousRendererCount; + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs.meta new file mode 100644 index 00000000..6e2ab16b --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPoolBurst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ad57195e4230c9344a64d902de871991 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs index 71906191..6ece01ff 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs @@ -1685,6 +1685,9 @@ namespace UnityEngine.Rendering //Ensure that all currently loaded scenes belong to the same set. foreach (var data in perSceneDataList) { + if (UnityEditor.SceneManagement.EditorSceneManager.IsPreviewScene(data.gameObject.scene)) + continue; // Ignore preview scenes - they are needed to make closed subscenes work + var set = ProbeVolumeBakingSet.GetBakingSetForScene(data.gameObject.scene); if (set != bakingSet) return false; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl index 97d58df8..73e63fd8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl @@ -749,6 +749,7 @@ void EvaluateAPVL1L2(APVSample apvSample, float3 N, out float3 diffuseLighting) // ------------------------------------------------------------- void EvaluateAdaptiveProbeVolume(APVSample apvSample, float3 normalWS, out float3 bakeDiffuseLighting) { + bakeDiffuseLighting = float3(0.0f, 0.0f, 0.0f); if (apvSample.status != APV_SAMPLE_STATUS_INVALID) { apvSample.Decode(); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumePerSceneData.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumePerSceneData.cs index 4fc973f5..6cc04a60 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumePerSceneData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumePerSceneData.cs @@ -95,7 +95,7 @@ namespace UnityEngine.Rendering void OnEnable() { - #if UNITY_EDITOR +#if UNITY_EDITOR // In the editor, always refresh the GUID as it may become out of date is scene is duplicated or other weird things // This field is serialized, so it will be available in standalones, where it can't change anymore. // Only change the GUID if the new one is valid. @@ -105,7 +105,7 @@ namespace UnityEngine.Rendering sceneGUID = newGUID; EditorUtility.SetDirty(this); } - #endif +#endif ProbeReferenceVolume.instance.RegisterPerSceneData(this); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareDataSRP.cs b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareDataSRP.cs index 61945b8f..4db6db78 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareDataSRP.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareDataSRP.cs @@ -1,4 +1,3 @@ -using NUnit.Framework; using UnityEngine.Serialization; namespace UnityEngine.Rendering diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs index cb9e6d8e..ceb9ff8c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs @@ -228,6 +228,10 @@ namespace UnityEngine.Rendering.RenderGraphModule /// to match the index passed to SetInputAttachment for this texture. /// /// + /// + /// This API is not universally supported across all platforms. In particular, using input attachments in combination with MSAA may be unsupported on certain targets. + /// To ensure compatibility, use `RenderGraphUtils.IsFramebufferFetchSupportedOnCurrentPlatform` to verify support at runtime, as platform capabilities may vary. + /// /// Texture to use during this pass. /// Index the shader will use to access this texture. /// How this pass will access the texture. Default value is set to AccessFlag.Read. Writing is currently not supported on any platform. diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs index f28e7357..8913e109 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs @@ -529,7 +529,7 @@ namespace UnityEngine.Rendering.RenderGraphModule nativeCompiler?.Cleanup(); m_CompilationCache?.Clear(); - + DelegateHashCodeUtils.ClearCache(); } @@ -751,6 +751,25 @@ namespace UnityEngine.Rendering.RenderGraphModule return m_Resources.CreateTexture(m_Resources.GetTextureResourceDesc(texture.handle)); } + /// + /// Create a new Render Graph Texture resource using the descriptor from another texture. + /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// + /// Texture from which the descriptor should be used. + /// The destination texture name. + /// Texture needs to be cleared on first use. + /// A new TextureHandle. + public TextureHandle CreateTexture(TextureHandle texture, string name, bool clear = false) + { + var destinationDesc = GetTextureDesc(texture); + destinationDesc.name = name; + destinationDesc.clearBuffer = clear; + + return m_Resources.CreateTexture(destinationDesc); + } + /// /// Create a new Render Graph Texture if the passed handle is invalid and use said handle as output. /// If the passed handle is valid, no texture is created. diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs index c5248f75..5c1eac07 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using UnityEngine.Experimental.Rendering; +using static UnityEngine.Rendering.RenderGraphModule.RenderGraph; namespace UnityEngine.Rendering.RenderGraphModule { @@ -399,6 +400,8 @@ namespace UnityEngine.Rendering.RenderGraphModule public void SetInputAttachment(TextureHandle tex, int index, AccessFlags flags, int mipLevel, int depthSlice) { + CheckFrameBufferFetchEmulationIsSupported(tex); + CheckUseFragment(tex, false); ResourceHandle result = UseResource(tex.handle, flags); // Note the version for the attachments is a bit arbitrary so we just use the latest for now @@ -514,6 +517,25 @@ namespace UnityEngine.Rendering.RenderGraphModule } } + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckFrameBufferFetchEmulationIsSupported(in TextureHandle tex) + { + if (enableValidityChecks) + { + if (!Util.RenderGraphUtils.IsFramebufferFetchEmulationSupportedOnCurrentPlatform()) + { + throw new InvalidOperationException($"This API is not supported on the current platform: {SystemInfo.graphicsDeviceType}"); + } + + if (!Util.RenderGraphUtils.IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform()) + { + var sourceInfo = m_RenderGraph.GetRenderTargetInfo(tex); + if (sourceInfo.bindMS) + throw new InvalidOperationException($"This API is not supported with MSAA attachments on the current platform: {SystemInfo.graphicsDeviceType}"); + } + } + } + public void SetShadingRateImageAttachment(in TextureHandle sriTextureHandle) { CheckNotUseFragment(sriTextureHandle); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs index 922466b7..7eece9d0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs @@ -17,6 +17,9 @@ namespace UnityEngine.Rendering.RenderGraphModule.Util /// Returns true if the shader features required by the copy pass is supported for MSAA, otherwise will it return false. public static bool CanAddCopyPassMSAA() { + if (!IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform()) + return false; + return Blitter.CanCopyMSAA(); } @@ -27,9 +30,53 @@ namespace UnityEngine.Rendering.RenderGraphModule.Util /// Returns true if the shader features required by the copy pass is supported for MSAA, otherwise will it return false. public static bool CanAddCopyPassMSAA(in TextureDesc sourceDesc) { + if (!IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform()) + return false; + return Blitter.CanCopyMSAA(sourceDesc); } + internal static bool IsFramebufferFetchEmulationSupportedOnCurrentPlatform() + { +#if PLATFORM_WEBGL + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3) + return false; +#endif + return true; + } + + internal static bool IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform() + { + // TODO: Temporarily disable this utility pending a more efficient solution for supporting or disabling framebuffer fetch emulation on PS4/PS5. + return (SystemInfo.graphicsDeviceType != GraphicsDeviceType.PlayStation4 + && SystemInfo.graphicsDeviceType != GraphicsDeviceType.PlayStation5 && SystemInfo.graphicsDeviceType != GraphicsDeviceType.PlayStation5NGGC); + } + + /// + /// Determines whether framebuffer fetch is supported on the current platform for the given texture. + /// This includes checking both general support for framebuffer fetch emulation and specific support + /// for multisampled (MSAA) textures. + /// + /// The RenderGraph adding this pass to. + /// The texture handle to validate for framebuffer fetch compatibility. + /// + /// Returns true if framebuffer fetch is supported on the current platform for the given texture; + /// otherwise, returns false. + /// + public static bool IsFramebufferFetchSupportedOnCurrentPlatform(this RenderGraph graph, in TextureHandle tex) + { + if (!IsFramebufferFetchEmulationSupportedOnCurrentPlatform()) + return false; + + if (!IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform()) + { + var sourceInfo = graph.GetRenderTargetInfo(tex); + if (sourceInfo.msaaSamples > 1) + return sourceInfo.bindMS; + } + return true; + } + class CopyPassData { public bool isMSAA; @@ -90,7 +137,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.Util // It would have 1 if the MSAA pass is not able to be used for target and 2 otherwise. // https://docs.unity3d.com/2017.4/Documentation/Manual/SL-ShaderCompileTargets.html // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-to-get-sample-position - if (isMSAA && !Blitter.CanCopyMSAA(sourceDesc)) + if (isMSAA && !CanAddCopyPassMSAA(sourceDesc)) throw new ArgumentException("Target does not support MSAA for AddCopyPass. Please use the blit alternative or use non MSAA textures."); using (var builder = graph.AddRasterRenderPass(passName, out var passData, file, line)) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderPipelineResources/GPUDriven/InstanceOcclusionCullingKernels.compute b/Packages/com.unity.render-pipelines.core/Runtime/RenderPipelineResources/GPUDriven/InstanceOcclusionCullingKernels.compute index 883bfe6c..fd055762 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderPipelineResources/GPUDriven/InstanceOcclusionCullingKernels.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderPipelineResources/GPUDriven/InstanceOcclusionCullingKernels.compute @@ -61,7 +61,7 @@ SphereBound LoadInstanceBoundingSphere(uint instanceID) { float4 data = asfloat(_InstanceDataBuffer.Load4(_BoundingSphereInstanceDataAddress + instanceID * 16)); SphereBound b; - b.center = data.xyz; + b.center = data.xyz; b.radius = data.w; return b; } @@ -105,7 +105,7 @@ void CopyInstances(uint dispatchIdx : SV_DispatchThreadID) uint argsBase = DRAW_ARGS_INDEX(dispatchIdx); _DrawArgs[argsBase + 0] = drawInfo.indexCount; // IndirectDrawIndexedArgs.indexCountPerInstance - _DrawArgs[argsBase + 1] = drawInfo.maxInstanceCount << _InstanceMultiplierShift; // IndirectDrawIndexedArgs.instanceCount + _DrawArgs[argsBase + 1] = (drawInfo.maxInstanceCountAndTopology >> 3) << _InstanceMultiplierShift; // IndirectDrawIndexedArgs.instanceCount _DrawArgs[argsBase + 2] = drawInfo.firstIndex; // IndirectDrawIndexedArgs.startIndex _DrawArgs[argsBase + 3] = drawInfo.baseVertex; // IndirectDrawIndexedArgs.baseVertexIndex _DrawArgs[argsBase + 4] = 0; // IndirectDrawIndexedArgs.startInstance @@ -120,6 +120,19 @@ void CopyInstances(uint dispatchIdx : SV_DispatchThreadID) } } +uint GetPrimitiveCount(uint indexCount, uint topology, bool nativeQuads) +{ + switch (topology) + { + case /*MeshTopology.Triangles*/ 0: return indexCount / 3; + case /*MeshTopology.Quads*/ 2: return nativeQuads ? (indexCount / 4) : (indexCount / 4 * 2); + case /*MeshTopology.Lines*/ 3: return indexCount / 2; + case /*MeshTopology.LineStrip*/ 4: return (indexCount >= 1) ? (indexCount - 1) : 0; + case /*MeshTopology.Points*/ 5: return indexCount; + default: return 0; + } +} + [numthreads(64,1,1)] void CullInstances(uint instanceInfoOffset : SV_DispatchThreadID) { @@ -157,7 +170,7 @@ void CullInstances(uint instanceInfoOffset : SV_DispatchThreadID) isOccludedInAll = false; } isVisible = !isOccludedInAll; - + #ifdef OCCLUSION_FIRST_PASS // if we failed the occlusion check, then add to the list for the second pass if (!isVisible) @@ -173,8 +186,16 @@ void CullInstances(uint instanceInfoOffset : SV_DispatchThreadID) if (_DebugCounterIndex >= 0) { // TODO: sum each within wave, first thread in wave issues atomic add to memory - int counterIndex = isVisible ? INSTANCEOCCLUSIONTESTDEBUGCOUNTER_NOT_OCCLUDED : INSTANCEOCCLUSIONTESTDEBUGCOUNTER_OCCLUDED; + int counterIndex = isVisible ? INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_NOT_OCCLUDED : INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_OCCLUDED; InterlockedAdd(_OcclusionDebugCounters[_DebugCounterIndex*INSTANCEOCCLUSIONTESTDEBUGCOUNTER_COUNT + counterIndex], 1); + + IndirectDrawInfo drawInfo = LoadDrawInfo(drawOffset); + uint argsBase = DRAW_ARGS_INDEX(drawOffset); + uint indexCount = _DrawArgs[argsBase + 0]; // IndirectDrawIndexedArgs.indexCountPerInstance + uint topology = drawInfo.maxInstanceCountAndTopology & 7; + uint primitiveCount = GetPrimitiveCount(indexCount, topology, false); + counterIndex = isVisible ? INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_NOT_OCCLUDED : INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_OCCLUDED; + InterlockedAdd(_OcclusionDebugCounters[_DebugCounterIndex*INSTANCEOCCLUSIONTESTDEBUGCOUNTER_COUNT + counterIndex], primitiveCount); } if (isVisible) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs index 421eadd8..d007439e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs @@ -137,11 +137,23 @@ namespace UnityEngine.Rendering .OrderBy(i => i.Item1) .ToList(); } + + Type[] m_BaseComponentTypeArray; /// /// The current list of all available types that derive from . /// - public Type[] baseComponentTypeArray { get; internal set; } // internal only for tests + public Type[] baseComponentTypeArray + { + get + { + if (isInitialized) + return m_BaseComponentTypeArray; + + throw new InvalidOperationException($"{nameof(VolumeManager)}.{nameof(instance)}.{nameof(baseComponentTypeArray)} cannot be called before the {nameof(VolumeManager)} is initialized. (See {nameof(VolumeManager)}.{nameof(instance)}.{nameof(isInitialized)} and {nameof(RenderPipelineManager)} for creation callback)."); + } + internal set => m_BaseComponentTypeArray = value; // internal only for tests + } /// /// Global default profile that provides default values for volume components. VolumeManager applies @@ -242,13 +254,19 @@ namespace UnityEngine.Rendering Debug.Assert(m_CreatedVolumeStacks.Count == 0); LoadBaseTypes(GraphicsSettings.currentRenderPipelineAssetType); + InitializeInternal(globalDefaultVolumeProfile, qualityDefaultVolumeProfile); + } + + //This is called by test where the basetypes are tuned for the purpose of the test. + internal void InitializeInternal(VolumeProfile globalDefaultVolumeProfile = null, VolumeProfile qualityDefaultVolumeProfile = null) + { InitializeVolumeComponents(); globalDefaultProfile = globalDefaultVolumeProfile; qualityDefaultProfile = qualityDefaultVolumeProfile; EvaluateVolumeDefaultState(); - m_DefaultStack = CreateStack(); + m_DefaultStack = CreateStackInternal(); stack = m_DefaultStack; isInitialized = true; @@ -347,9 +365,17 @@ namespace UnityEngine.Rendering /// /// public VolumeStack CreateStack() + { + if (!isInitialized) + throw new InvalidOperationException($"{nameof(VolumeManager)}.{nameof(instance)}.{nameof(CreateStack)}() cannot be called before the {nameof(VolumeManager)} is initialized. (See {nameof(VolumeManager)}.{nameof(instance)}.{nameof(isInitialized)} and {nameof(RenderPipelineManager)} for creation callback)."); + + return CreateStackInternal(); + } + + VolumeStack CreateStackInternal() { var stack = new VolumeStack(); - stack.Reload(baseComponentTypeArray); + stack.Reload(m_BaseComponentTypeArray); m_CreatedVolumeStacks.Add(stack); return stack; } @@ -421,15 +447,18 @@ namespace UnityEngine.Rendering list.Add(t); } - baseComponentTypeArray = list.ToArray(); + m_BaseComponentTypeArray = list.ToArray(); } } internal void InitializeVolumeComponents() { + if (m_BaseComponentTypeArray == null || m_BaseComponentTypeArray.Length == 0) + return; + // Call custom static Init method if present var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; - foreach (var type in baseComponentTypeArray) + foreach (var type in m_BaseComponentTypeArray) { var initMethod = type.GetMethod("Init", flags); if (initMethod != null) @@ -440,9 +469,9 @@ namespace UnityEngine.Rendering } // Evaluate static default values for VolumeComponents, which is the baseline to reset the values to at the start of Update. - internal void EvaluateVolumeDefaultState() + void EvaluateVolumeDefaultState() { - if (baseComponentTypeArray == null || baseComponentTypeArray.Length == 0) + if (m_BaseComponentTypeArray == null || m_BaseComponentTypeArray.Length == 0) return; using var profilerScope = k_ProfilerMarkerEvaluateVolumeDefaultState.Auto(); @@ -453,7 +482,7 @@ namespace UnityEngine.Rendering // First, default-construct all VolumeComponents List componentsDefaultStateList = new(); - foreach (var type in baseComponentTypeArray) + foreach (var type in m_BaseComponentTypeArray) { componentsDefaultStateList.Add((VolumeComponent) ScriptableObject.CreateInstance(type)); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs index 65c9de7b..22cc9761 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs @@ -24,6 +24,7 @@ namespace UnityEngine.Experimental.Rendering internal int cullingPassId; internal bool copyDepth; internal bool hasMotionVectorPass; + internal bool spaceWarpRightHandedNDC; #if ENABLE_VR && ENABLE_XR_MODULE internal UnityEngine.XR.XRDisplaySubsystem.XRRenderPass xrSdkRenderPass; @@ -105,6 +106,22 @@ namespace UnityEngine.Experimental.Rendering /// public bool hasMotionVectorPass { get; private set; } + /// + /// Reports which NDC convention the render pipeline should use when calculating motion vectors. + /// if true, motion vector data must use the right-handed NDC space. If false motion vector data + /// must use the left-handed NDC space. + /// + /// + /// The render pipeline must write motion vector data to the . + /// + /// > [!NOTE] + /// > The OpenXR specification doesn't specify which coordinate space convention to use for the + /// > motion vector data. Unity only supports SpaceWarp when using the Vulkan graphics API, which uses the right-handed convention for normalized device coordinates, but + /// > devices still can choose either convention for motion data when the + /// > application is using the Vulkan graphics API. + /// + public bool spaceWarpRightHandedNDC { get; private set; } + /// /// If true, is the first pass of a xr camera /// @@ -480,6 +497,7 @@ namespace UnityEngine.Experimental.Rendering motionVectorRenderTarget = new RenderTargetIdentifier(createInfo.motionVectorRenderTarget, 0, CubemapFace.Unknown, -1); motionVectorRenderTargetDesc = createInfo.motionVectorRenderTargetDesc; hasMotionVectorPass = createInfo.hasMotionVectorPass; + spaceWarpRightHandedNDC = createInfo.spaceWarpRightHandedNDC; m_OcclusionMesh.SetMaterial(createInfo.occlusionMeshMaterial); occlusionMeshScale = createInfo.occlusionMeshScale; foveatedRenderingInfo = createInfo.foveatedRenderingInfo; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs index aa80bd23..62f25ce4 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs @@ -533,6 +533,7 @@ namespace UnityEngine.Experimental.Rendering multipassId = layout.GetActivePasses().Count, cullingPassId = xrRenderPass.cullingPassIndex, copyDepth = xrRenderPass.shouldFillOutDepth, + spaceWarpRightHandedNDC = xrRenderPass.spaceWarpRightHandedNDC, xrSdkRenderPass = xrRenderPass }; diff --git a/Packages/com.unity.render-pipelines.core/package.json b/Packages/com.unity.render-pipelines.core/package.json index c92b4e97..8e9bebb6 100644 --- a/Packages/com.unity.render-pipelines.core/package.json +++ b/Packages/com.unity.render-pipelines.core/package.json @@ -14,5 +14,5 @@ "com.unity.modules.jsonserialize": "1.0.0", "com.unity.rendering.light-transport": "1.0.1" }, - "_fingerprint": "71b4bdac1964f74b866160605ee9150cf79ab359" + "_fingerprint": "943f3af6fe14719bad5cae2cf73687f86e685e1b" } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs index 78c94c8a..62f10b21 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs @@ -630,9 +630,9 @@ namespace UnityEditor.Rendering.HighDefinition m_SizeValues[axe].floatValue = newSize; } - internal void MinMaxSliderWithFields(GUIContent label, ref float minValue, ref float maxValue, float minLimit, float maxLimit) + internal void MinMaxSliderWithFields(Rect rect, GUIContent label, ref float minValue, ref float maxValue, float minLimit, float maxLimit) { - var rect = EditorGUILayout.GetControlRect(); + // Reserve label space and push the slider rect to the right rect = EditorGUI.PrefixLabel(rect, label); const float fieldWidth = 40, padding = 4; @@ -662,6 +662,45 @@ namespace UnityEditor.Rendering.HighDefinition } } + void DoRenderingLayerMask() + { + Rect rect = EditorGUILayout.GetControlRect(true, 18f); + EditorGUI.BeginProperty(rect, k_DecalLayerMaskContent, m_DecalLayerMask); + + var mask = m_DecalLayerMask.uintValue; + EditorGUI.BeginChangeCheck(); + mask = EditorGUI.RenderingLayerMaskField(rect, k_DecalLayerMaskContent, (RenderingLayerMask)mask, EditorStyles.layerMaskField); + if (EditorGUI.EndChangeCheck()) + { + m_DecalLayerMask.intValue = unchecked((int) mask); + serializedObject.ApplyModifiedProperties(); + } + + EditorGUI.EndProperty(); + } + + void DoAngleFade() + { + // The slider edits 2 different properties. Both can be overridden separately. + var rect = EditorGUILayout.GetControlRect(); + EditorGUI.BeginProperty(rect, k_AngleFadeContent, m_StartAngleFadeProperty); + EditorGUI.BeginProperty(rect, k_AngleFadeContent, m_EndAngleFadeProperty); + + float angleFadeMinValue = m_StartAngleFadeProperty.floatValue; + float angleFadeMaxValue = m_EndAngleFadeProperty.floatValue; + EditorGUI.BeginChangeCheck(); + MinMaxSliderWithFields(rect,k_AngleFadeContent, ref angleFadeMinValue, ref angleFadeMaxValue, 0.0f, 180.0f); + if (EditorGUI.EndChangeCheck()) + { + m_StartAngleFadeProperty.floatValue = angleFadeMinValue; + m_EndAngleFadeProperty.floatValue = angleFadeMaxValue; + serializedObject.ApplyModifiedProperties(); + } + + EditorGUI.EndProperty(); + EditorGUI.EndProperty(); + } + public override void OnInspectorGUI() { bool supportDecals = false; @@ -735,14 +774,7 @@ namespace UnityEditor.Rendering.HighDefinition decalLayerEnabled = supportDecals && hdrp.currentPlatformRenderPipelineSettings.supportDecalLayers; using (new EditorGUI.DisabledScope(!decalLayerEnabled)) { - var mask = m_DecalLayerMask.uintValue; - EditorGUI.BeginChangeCheck(); - mask = EditorGUILayout.RenderingLayerMaskField(k_DecalLayerMaskContent, mask); - if (EditorGUI.EndChangeCheck()) - { - m_DecalLayerMask.intValue = unchecked((int) mask); - EditorUtility.SetDirty(m_DecalLayerMask.serializedObject.targetObject); - } + DoRenderingLayerMask(); } } @@ -758,15 +790,7 @@ namespace UnityEditor.Rendering.HighDefinition EditorGUILayout.PropertyField(m_FadeScaleProperty, k_FadeScaleContent); using (new EditorGUI.DisabledScope(!decalLayerEnabled)) { - float angleFadeMinValue = m_StartAngleFadeProperty.floatValue; - float angleFadeMaxValue = m_EndAngleFadeProperty.floatValue; - EditorGUI.BeginChangeCheck(); - MinMaxSliderWithFields(k_AngleFadeContent, ref angleFadeMinValue, ref angleFadeMaxValue, 0.0f, 180.0f); - if (EditorGUI.EndChangeCheck()) - { - m_StartAngleFadeProperty.floatValue = angleFadeMinValue; - m_EndAngleFadeProperty.floatValue = angleFadeMaxValue; - } + DoAngleFade(); } if (!decalLayerEnabled) @@ -985,7 +1009,7 @@ namespace UnityEditor.Rendering.HighDefinition } if (shader != null) - { + { var material = new Material(shader); AssetDatabase.CreateAsset(material, materialName); ProjectWindowUtil.ShowCreatedAsset(material); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/FogVolumePropertyBlock.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/FogVolumePropertyBlock.cs index 1400885b..fd745434 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/FogVolumePropertyBlock.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/FogVolumePropertyBlock.cs @@ -20,6 +20,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph public static GUIContent blendMode = new GUIContent("Blend Mode", "Determines how the fog volume will blend with other fogs in the scene."); public static GUIContent singleScatteringAlbedo = new GUIContent("Single Scattering Albedo", "The color this fog scatters light to."); public static GUIContent fogDistance = new GUIContent("Fog Distance", "Density at the base of the fog. Determines how far you can see through the fog in meters."); + public static GUIContent debugSymbolsText = new GUIContent("Debug Symbols", "When enabled, HDRP activates d3d11 debug symbols for this Shader."); } protected override string title => "Fog Volume Options"; @@ -35,6 +36,9 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph // AddProperty(Styles.singleScatteringAlbedo, () => fogData.singleScatteringAlbedo, (newValue) => fogData.singleScatteringAlbedo = newValue); // AddProperty(Styles.fogDistance, () => fogData.fogDistance, (newValue) => fogData.fogDistance = newValue); AddProperty(Styles.blendMode, () => fogData.blendMode, (newValue) => fogData.blendMode = newValue); + + if (Unsupported.IsDeveloperMode()) + AddProperty(Styles.debugSymbolsText, () => systemData.debugSymbols, (newValue) => systemData.debugSymbols = newValue); } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/FogVolumeSubTarget.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/FogVolumeSubTarget.cs index 5d10995e..3b5279bb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/FogVolumeSubTarget.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/FogVolumeSubTarget.cs @@ -172,7 +172,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph { // Definition displayName = HDShaderPassNames.s_FogVolumeVoxelizeStr, - referenceName = "SHADERPASS_FOGVOLUME_VOXELIZATION", + referenceName = "SHADERPASS_FOG_VOLUME_VOXELIZATION", lightMode = HDShaderPassNames.s_FogVolumeVoxelizeStr, useInPreview = false, @@ -200,7 +200,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph { // Definition displayName = "ShaderGraphPreview", - referenceName = "SHADERPASS_FOGVOLUME_PREVIEW", + referenceName = "SHADERPASS_FOG_VOLUME_PREVIEW", lightMode = "ShaderGraphPreview", useInPreview = true, @@ -228,7 +228,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph { // Definition displayName = HDShaderPassNames.s_VolumetricFogVFXOverdrawDebugStr, - referenceName = "SHADERPASS_FOGVOLUME_OVERDRAW_DEBUG", + referenceName = "SHADERPASS_FOG_VOLUME_OVERDRAW_DEBUG", lightMode = HDShaderPassNames.s_VolumetricFogVFXOverdrawDebugStr, useInPreview = true, @@ -308,6 +308,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph const string kPacking = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"; const string kColor = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"; const string kFunctions = "Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl"; + const string kVoxelizationTransforms = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl"; const string kVoxelizePass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl"; const string kPreviewPass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl"; const string kOverdrawPass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl"; @@ -318,6 +319,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph { kColor, IncludeLocation.Pregraph }, { kFunctions, IncludeLocation.Pregraph }, { CoreIncludes.MinimalCorePregraph }, + { kVoxelizationTransforms, IncludeLocation.Pregraph }, { kVoxelizePass, IncludeLocation.Postgraph }, }; diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl index 7e079bfa..24b54722 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl @@ -1,4 +1,4 @@ -#if SHADERPASS != SHADERPASS_FOGVOLUME_OVERDRAW_DEBUG +#if SHADERPASS != SHADERPASS_FOG_VOLUME_OVERDRAW_DEBUG #error SHADERPASS_is_not_correctly_define #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl index bd90a161..cc785e80 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl @@ -1,4 +1,4 @@ -#if SHADERPASS != SHADERPASS_FOGVOLUME_PREVIEW +#if SHADERPASS != SHADERPASS_FOG_VOLUME_PREVIEW #error SHADERPASS_is_not_correctly_define #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl index 2f0ab60c..3f5e933c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl @@ -1,4 +1,4 @@ -#if SHADERPASS != SHADERPASS_FOGVOLUME_VOXELIZATION +#if SHADERPASS != SHADERPASS_FOG_VOLUME_VOXELIZATION #error SHADERPASS_is_not_correctly_define #endif @@ -91,14 +91,13 @@ VertexToFragment Vert(uint instanceId : INSTANCEID_SEMANTIC, uint vertexId : VER return output; } -FragInputs BuildFragInputs(VertexToFragment v2f, float3 voxelPositionOS, float3 voxelClipSpace) +FragInputs BuildFragInputs(VertexToFragment v2f, float3 voxelPositionWS, float3 voxelClipSpace) { FragInputs output; ZERO_INITIALIZE(FragInputs, output); - float3 positionWS = mul(UNITY_MATRIX_M, float4(voxelPositionOS, 1)).xyz; output.positionSS = v2f.positionCS; - output.positionRWS = output.positionPredisplacementRWS = positionWS; + output.positionRWS = output.positionPredisplacementRWS = voxelPositionWS; output.positionPixel = uint2(v2f.positionCS.xy); output.texCoord0 = float4(saturate(voxelClipSpace * 0.5 + 0.5), 0); output.tangentToWorld = k_identity3x3; @@ -140,9 +139,11 @@ void Frag(VertexToFragment v2f, out float4 outColor : SV_Target0) float3 rayoriginWS = GetCurrentViewPosition(); float3 voxelCenterWS = rayoriginWS + sliceDistance * raycenterDirWS; + // Build rotation matrix from normalized OBB axes to transform the world space position float3x3 obbFrame = float3x3(_VolumetricMaterialObbRight.xyz, _VolumetricMaterialObbUp.xyz, cross(_VolumetricMaterialObbRight.xyz, _VolumetricMaterialObbUp.xyz)); - float3 voxelCenterBS = mul(voxelCenterWS - _VolumetricMaterialObbCenter.xyz + _WorldSpaceCameraPos.xyz, transpose(obbFrame)); + // Rotate world position around the center of the local fog OBB + float3 voxelCenterBS = mul(GetAbsolutePositionWS(voxelCenterWS - _VolumetricMaterialObbCenter.xyz), transpose(obbFrame)); float3 voxelCenterCS = (voxelCenterBS * rcp(_VolumetricMaterialObbExtents.xyz)); // Still need to clip pixels outside of the box because of the froxel buffer shape @@ -150,7 +151,7 @@ void Frag(VertexToFragment v2f, out float4 outColor : SV_Target0) if (!overlap) clip(-1); - FragInputs fragInputs = BuildFragInputs(v2f, voxelCenterBS, voxelCenterCS); + FragInputs fragInputs = BuildFragInputs(v2f, voxelCenterWS, voxelCenterCS); GetVolumeData(fragInputs, v2f.viewDirectionWS, albedo, extinction); // Accumulate volume parameters diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl new file mode 100644 index 00000000..44ad1219 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl @@ -0,0 +1,36 @@ +#pragma once + +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl" + +// Overrides the transform functions that would use object matrices in the fog as they are not available due to the indirect draw +// Instead we can re-build the object matrix from the OBB of the fog object + +float4x4 BuildWorldToObjectMatrixFromLocalFogOBB() +{ + float3x3 rotation = float3x3( + _VolumetricMaterialObbRight.xyz, + _VolumetricMaterialObbUp.xyz, + cross(_VolumetricMaterialObbRight.xyz, _VolumetricMaterialObbUp.xyz) + ); + + // inverse rotation + rotation = transpose(rotation); + + // inverse translation + float3 inverseTranslation = -(mul(_VolumetricMaterialObbCenter.xyz, rotation)); + + // Build matrix + float4x4 objectMatrix = 0; + objectMatrix._m00_m10_m20 = rotation[0]; + objectMatrix._m01_m11_m21 = rotation[1]; + objectMatrix._m02_m12_m22 = rotation[2]; + objectMatrix._m03_m13_m23_m33 = float4(inverseTranslation, 1); + + return objectMatrix; +} + +float3 TransformWorldToObjectFog(float3 positionRWS) +{ + float3 posWS = GetAbsolutePositionWS(positionRWS); + return mul(BuildWorldToObjectMatrixFromLocalFogOBB(), float4(posWS, 1)).xyz; +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl.meta new file mode 100644 index 00000000..33154246 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/VoxelizationTransforms.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 623770b432f006f49af1b65f726bf86f +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Pixel.template.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Pixel.template.hlsl index 07067034..11bb670a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Pixel.template.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Pixel.template.hlsl @@ -25,12 +25,20 @@ SurfaceDescriptionInputs FragInputsToSurfaceDescriptionInputs(FragInputs input, $SurfaceDescriptionInputs.TangentSpaceViewDirection: float3x3 tangentSpaceTransform = float3x3(output.WorldSpaceTangent,output.WorldSpaceBiTangent,output.WorldSpaceNormal); $SurfaceDescriptionInputs.TangentSpaceViewDirection: output.TangentSpaceViewDirection = TransformWorldToTangent(output.WorldSpaceViewDirection, tangentSpaceTransform); $SurfaceDescriptionInputs.WorldSpacePosition: output.WorldSpacePosition = input.positionRWS; +#if SHADERPASS != SHADERPASS_FOG_VOLUME_VOXELIZATION $SurfaceDescriptionInputs.ObjectSpacePosition: output.ObjectSpacePosition = TransformWorldToObject(input.positionRWS); +#else + $SurfaceDescriptionInputs.ObjectSpacePosition: output.ObjectSpacePosition = TransformWorldToObjectFog(input.positionRWS); +#endif $SurfaceDescriptionInputs.ViewSpacePosition: output.ViewSpacePosition = TransformWorldToView(input.positionRWS); $SurfaceDescriptionInputs.TangentSpacePosition: output.TangentSpacePosition = float3(0.0f, 0.0f, 0.0f); $SurfaceDescriptionInputs.AbsoluteWorldSpacePosition: output.AbsoluteWorldSpacePosition = GetAbsolutePositionWS(input.positionRWS); $SurfaceDescriptionInputs.WorldSpacePositionPredisplacement: output.WorldSpacePositionPredisplacement = input.positionPredisplacementRWS; +#if SHADERPASS != SHADERPASS_FOG_VOLUME_VOXELIZATION $SurfaceDescriptionInputs.ObjectSpacePositionPredisplacement: output.ObjectSpacePositionPredisplacement = TransformWorldToObject(input.positionPredisplacementRWS); +#else + $SurfaceDescriptionInputs.ObjectSpacePositionPredisplacement: output.ObjectSpacePositionPredisplacement = TransformWorldToObjectFog(input.positionPredisplacementRWS); +#endif $SurfaceDescriptionInputs.ViewSpacePositionPredisplacement: output.ViewSpacePositionPredisplacement = TransformWorldToView(input.positionPredisplacementRWS); $SurfaceDescriptionInputs.TangentSpacePositionPredisplacement: output.TangentSpacePositionPredisplacement = float3(0.0f, 0.0f, 0.0f); $SurfaceDescriptionInputs.AbsoluteWorldSpacePositionPredisplacement: output.AbsoluteWorldSpacePositionPredisplacement = GetAbsolutePositionWS(input.positionPredisplacementRWS); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs index 049bc962..57d787ca 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs @@ -1482,6 +1482,7 @@ namespace UnityEngine.Rendering.HighDefinition public bool decalsEnabled; public BufferHandle perVoxelOffset; + public BufferHandle lightList; public DBufferOutput dbuffer; public GBufferOutput gbuffer; public TextureHandle depthBuffer; @@ -1564,6 +1565,8 @@ namespace UnityEngine.Rendering.HighDefinition passData.decalsEnabled = (hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals)) && (DecalSystem.m_DecalDatasCount > 0); passData.perVoxelOffset = builder.ReadBuffer(lightLists.perVoxelOffset); + + passData.lightList = builder.ReadBuffer(lightLists.lightList); passData.dbuffer = ReadDBuffer(dbuffer, builder); passData.clearColorTexture = Compositor.CompositionManager.GetClearTextureForStackedCamera(hdCamera); // returns null if is not a stacked camera @@ -1583,6 +1586,9 @@ namespace UnityEngine.Rendering.HighDefinition BindDefaultTexturesLightingBuffers(context.defaultResources, context.cmd); + if (data.lightList.IsValid()) + context.cmd.SetGlobalBuffer(HDShaderIDs.g_vLightListTile, data.lightList); + BindDBufferGlobalData(data.dbuffer, context); DrawOpaqueRendererList(context, data.frameSettings, data.opaqueRendererList); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index 0807c021..0f0eb310 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -45,8 +45,7 @@ namespace UnityEngine.Rendering.HighDefinition // Caution: We require sun light here as some skies use the sun light to render, it means that UpdateSkyEnvironment must be called after PrepareLightsForGPU. // TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute). - if (!m_CurrentDebugDisplaySettings.IsMatcapViewEnabled(hdCamera)) - m_SkyManager.UpdateEnvironment(m_RenderGraph, hdCamera, GetMainLight(), m_CurrentDebugDisplaySettings); + m_SkyManager.UpdateEnvironment(m_RenderGraph, hdCamera, GetMainLight(), m_CurrentDebugDisplaySettings); // We need to initialize the MipChainInfo here, so it will be available to any render graph pass that wants to use it during setup // Be careful, ComputePackedMipChainInfo needs the render texture size and not the viewport size. Otherwise it would compute the wrong size. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingLightLoop.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingLightLoop.hlsl index 3d1f5754..b2469ecd 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingLightLoop.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingLightLoop.hlsl @@ -24,7 +24,8 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS { // Init LightLoop output structure ZERO_INITIALIZE(LightLoopOutput, lightLoopOutput); - + ApplyCameraRelativeXR(posInput.positionWS); + LightLoopContext context; context.contactShadow = 1.0; context.shadowContext = InitShadowContext(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs index 3cd5604c..d1ccc6be 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs @@ -34,5 +34,8 @@ namespace UnityEngine.Rendering.HighDefinition Constant, FullScreenDebug, PBRSky, + FogVolumePreview, + FogVolumeVoxelization, + FogVolumeOverdrawDebug, } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl index 8ff52388..ee5aadc6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl @@ -35,6 +35,9 @@ #define SHADERPASS_CONSTANT (25) #define SHADERPASS_FULL_SCREEN_DEBUG (26) #define SHADERPASS_PBRSKY (27) +#define SHADERPASS_FOG_VOLUME_PREVIEW (28) +#define SHADERPASS_FOG_VOLUME_VOXELIZATION (29) +#define SHADERPASS_FOG_VOLUME_OVERDRAW_DEBUG (30) #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs index 0ca9f691..43059815 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs @@ -1236,41 +1236,49 @@ namespace UnityEngine.Rendering.HighDefinition m_CurrentDebugDisplaySettings = debugSettings; m_CurrentSunLight = sunLight; - SkyAmbientMode ambientMode = hdCamera.volumeStack.GetComponent().skyAmbientMode.value; + if (debugSettings.IsMatcapViewEnabled(hdCamera)) + { + HDRenderPipeline.SetGlobalTexture(renderGraph, HDShaderIDs._SkyTexture, m_BlackCubemapArray); + HDRenderPipeline.SetGlobalBuffer(renderGraph, HDShaderIDs._AmbientProbeData, m_BlackAmbientProbeBuffer); + } + else + { + SkyAmbientMode ambientMode = hdCamera.volumeStack.GetComponent().skyAmbientMode.value; - UpdateEnvironment(renderGraph, hdCamera, hdCamera.lightingSky, sunLight, m_UpdateRequired, ambientMode == SkyAmbientMode.Dynamic, false, ambientMode); + UpdateEnvironment(renderGraph, hdCamera, hdCamera.lightingSky, sunLight, m_UpdateRequired, ambientMode == SkyAmbientMode.Dynamic, false, ambientMode); - // Preview camera will have a different sun, therefore the hash for the static lighting sky will change and force a recomputation - // because we only maintain one static sky. Since we don't care that the static lighting may be a bit different in the preview we never recompute - // and we use the one from the main camera. - bool forceStaticUpdate = false; - m_ActiveStaticSky = m_StaticLightingSkies.GetValueOrDefault(SceneManager.GetActiveScene().GetHashCode(), null); + // Preview camera will have a different sun, therefore the hash for the static lighting sky will change and force a recomputation + // because we only maintain one static sky. Since we don't care that the static lighting may be a bit different in the preview we never recompute + // and we use the one from the main camera. + bool forceStaticUpdate = false; + m_ActiveStaticSky = m_StaticLightingSkies.GetValueOrDefault(SceneManager.GetActiveScene().GetHashCode(), null); #if UNITY_EDITOR - // In the editor, we might need the static sky ready for baking lightmaps/lightprobes regardless of the current ambient mode so we force it to update in this case if it's not been computed yet.. - // We always force an update of the static sky when we're in scene view mode. Previous behaviour was to prevent forced updates if the hash of the static sky was non-null, but this was preventing - // the lightmapper from updating in response to changes in environment. See GFXGI-237 for a better description of this issue. + // In the editor, we might need the static sky ready for baking lightmaps/lightprobes regardless of the current ambient mode so we force it to update in this case if it's not been computed yet.. + // We always force an update of the static sky when we're in scene view mode. Previous behaviour was to prevent forced updates if the hash of the static sky was non-null, but this was preventing + // the lightmapper from updating in response to changes in environment. See GFXGI-237 for a better description of this issue. - forceStaticUpdate = hdCamera.camera.cameraType == CameraType.SceneView; + forceStaticUpdate = hdCamera.camera.cameraType == CameraType.SceneView; #endif - if ((ambientMode == SkyAmbientMode.Static || forceStaticUpdate) && hdCamera.camera.cameraType != CameraType.Preview) - { - if (m_ActiveStaticSky != null) + if ((ambientMode == SkyAmbientMode.Static || forceStaticUpdate) && hdCamera.camera.cameraType != CameraType.Preview) { - m_StaticLightingSky.skySettings = m_ActiveStaticSky.skySettings; - m_StaticLightingSky.cloudSettings = m_ActiveStaticSky.cloudSettings; - m_StaticLightingSky.volumetricClouds = m_ActiveStaticSky.volumetricClouds; + if (m_ActiveStaticSky != null) + { + m_StaticLightingSky.skySettings = m_ActiveStaticSky.skySettings; + m_StaticLightingSky.cloudSettings = m_ActiveStaticSky.cloudSettings; + m_StaticLightingSky.volumetricClouds = m_ActiveStaticSky.volumetricClouds; + } + UpdateEnvironment(renderGraph, hdCamera, m_StaticLightingSky, sunLight, m_StaticSkyUpdateRequired || m_UpdateRequired, true, true, SkyAmbientMode.Static); + m_StaticSkyUpdateRequired = false; } - UpdateEnvironment(renderGraph, hdCamera, m_StaticLightingSky, sunLight, m_StaticSkyUpdateRequired || m_UpdateRequired, true, true, SkyAmbientMode.Static); - m_StaticSkyUpdateRequired = false; - } - m_UpdateRequired = false; + m_UpdateRequired = false; - SetGlobalSkyData(renderGraph, hdCamera.lightingSky, m_BuiltinParameters); + SetGlobalSkyData(renderGraph, hdCamera.lightingSky, m_BuiltinParameters); - // Keep global setter for now. We should probably remove it and set it explicitly where needed like any other resource. As is it breaks resource lifetime contract with render graph. - HDRenderPipeline.SetGlobalTexture(renderGraph, HDShaderIDs._SkyTexture, GetReflectionTexture(hdCamera.lightingSky)); - HDRenderPipeline.SetGlobalBuffer(renderGraph, HDShaderIDs._AmbientProbeData, GetDiffuseAmbientProbeBuffer(hdCamera)); + // Keep global setter for now. We should probably remove it and set it explicitly where needed like any other resource. As is it breaks resource lifetime contract with render graph. + HDRenderPipeline.SetGlobalTexture(renderGraph, HDShaderIDs._SkyTexture, GetReflectionTexture(hdCamera.lightingSky)); + HDRenderPipeline.SetGlobalBuffer(renderGraph, HDShaderIDs._AmbientProbeData, GetDiffuseAmbientProbeBuffer(hdCamera)); + } } static void UpdateBuiltinParameters(ref BuiltinSkyParameters builtinParameters, SkyUpdateContext skyContext, HDCamera hdCamera, Light sunLight, DebugDisplaySettings debugSettings) diff --git a/Packages/com.unity.render-pipelines.high-definition/package.json b/Packages/com.unity.render-pipelines.high-definition/package.json index 21c979fe..67eba72d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/package.json +++ b/Packages/com.unity.render-pipelines.high-definition/package.json @@ -100,5 +100,5 @@ ] } ], - "_fingerprint": "840db4b587bbd894c751a83052cd5c5a11fba2f2" + "_fingerprint": "3672d1571dfd5f4d1627647460e0e4e2f11422ae" } diff --git a/Packages/com.unity.rendering.light-transport/Runtime/UnifiedRayTracing/Common/TerrainToMesh.cs b/Packages/com.unity.rendering.light-transport/Runtime/UnifiedRayTracing/Common/TerrainToMesh.cs index ea69502c..32e150e3 100644 --- a/Packages/com.unity.rendering.light-transport/Runtime/UnifiedRayTracing/Common/TerrainToMesh.cs +++ b/Packages/com.unity.rendering.light-transport/Runtime/UnifiedRayTracing/Common/TerrainToMesh.cs @@ -10,54 +10,15 @@ namespace UnityEngine.Rendering.UnifiedRayTracing { static private AsyncTerrainToMeshRequest MakeAsyncTerrainToMeshRequest(int width, int height, Vector3 heightmapScale, float[,] heightmap, bool[,] holes) { - int vertexCount = width * height; + int vertexCount = width * height; var job = new ComputeTerrainMeshJob(); + job.heightmap = new NativeArray(vertexCount, Allocator.Persistent); + for (int i = 0; i < vertexCount; ++i) + job.heightmap[i] = heightmap[i / (width), i % (width)]; - //WW1MOD This crashes when baking 4k terrains, as it tries to allocate a *2GB* Buffer!.. which is fine *here* but when it gets uploaded to GPU, it goes crashy or error, depending on dx-API/Driver - //Note heightmap size is always pow2+1 - //the "else" part is the original code - if (height == 4097) - { - const int halfSize = 2049; - int _vertexCount = halfSize * halfSize; - - Debug.Log("Downsizing Terrain heightmap mesh output to 2k to prevent crashes"); - - job.heightmap = new NativeArray(_vertexCount, Allocator.Persistent); - for (int i = 0; i < _vertexCount; ++i) - { - float h0 = heightmap[((i*2)+0) / (width), ((i*2)+0) % (width)]; - float h1 = heightmap[((i*2)+1) / (width), ((i*2)+0) % (width)]; - float h2 = heightmap[((i*2)+0) / (width), ((i*2)+1) % (width)]; - float h3 = heightmap[((i*2)+1) / (width), ((i*2)+1) % (width)]; - - job.heightmap[i] = (h0 + h1 + h2 + h3) / 4f; - } - - job.holes = new NativeArray((halfSize - 1) * (halfSize - 1), Allocator.Persistent); - for (int i = 0; i < (halfSize - 1) * (halfSize - 1); ++i) - { - bool h0 = holes[((i*2)+0) / (width - 1), ((i*2)+0) % (width - 1)]; - bool h1 = holes[((i*2)+1) / (width - 1), ((i*2)+0) % (width - 1)]; - bool h2 = holes[((i*2)+0) / (width - 1), ((i*2)+1) % (width - 1)]; - bool h3 = holes[((i*2)+1) / (width - 1), ((i*2)+1) % (width - 1)]; - - job.holes[i] = h0 || h1 || h2 || h3; - } - - height = width = halfSize; - vertexCount = _vertexCount; - } - else - { - job.heightmap = new NativeArray(vertexCount, Allocator.Persistent); - for (int i = 0; i < vertexCount; ++i) - job.heightmap[i] = heightmap[i / (width), i % (width)]; - - job.holes = new NativeArray((width - 1) * (height - 1), Allocator.Persistent); - for (int i = 0; i < (width - 1) * (height - 1); ++i) - job.holes[i] = holes[i / (width - 1), i % (width - 1)]; - } + job.holes = new NativeArray((width - 1) * (height - 1), Allocator.Persistent); + for (int i = 0; i < (width - 1) * (height - 1); ++i) + job.holes[i] = holes[i / (width - 1), i % (width - 1)]; job.width = width; job.height = height; diff --git a/Packages/com.unity.rendering.light-transport/Tests/Editor/UnifiedRayTracing/AccelStructTests.cs b/Packages/com.unity.rendering.light-transport/Tests/Editor/UnifiedRayTracing/AccelStructTests.cs index 510c6c2e..7113ff55 100644 --- a/Packages/com.unity.rendering.light-transport/Tests/Editor/UnifiedRayTracing/AccelStructTests.cs +++ b/Packages/com.unity.rendering.light-transport/Tests/Editor/UnifiedRayTracing/AccelStructTests.cs @@ -170,6 +170,7 @@ namespace UnityEngine.Rendering.UnifiedRayTracing.Tests } [Test] + [Timeout(360000)] public void AddInstance_MeshWith2GBWorthOfVertices_Throws() { var resources = new RayTracingResources(); diff --git a/Packages/com.unity.rendering.light-transport/package.json b/Packages/com.unity.rendering.light-transport/package.json index d7a62805..6c0b217f 100644 --- a/Packages/com.unity.rendering.light-transport/package.json +++ b/Packages/com.unity.rendering.light-transport/package.json @@ -15,5 +15,5 @@ "pathtracing", "monte-carlo" ], - "_fingerprint": "ec31b4120e30d44c7f702fa7bfa50d70b562cd4a" + "_fingerprint": "e647573c7d2ae78386ecb3f9f962738597f13fcf" } diff --git a/Packages/com.unity.shadergraph/package.json b/Packages/com.unity.shadergraph/package.json index 0a779f44..68bd7d2a 100644 --- a/Packages/com.unity.shadergraph/package.json +++ b/Packages/com.unity.shadergraph/package.json @@ -43,5 +43,5 @@ "path": "Samples~/UGUIShaders" } ], - "_fingerprint": "e5d3455aa13376f767ad6bf5f3faab2073877176" + "_fingerprint": "8d13f365c6632c6b398ae9cd01d13bcee9880a3b" } diff --git a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Image.cs b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Image.cs index abdb7060..3733bb80 100644 --- a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Image.cs +++ b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Image.cs @@ -935,15 +935,15 @@ namespace UnityEngine.UI internal SecondarySpriteTexture [] secondaryTextures => m_SecondaryTextures; // Internal for testing only - static void ClearArray(SecondarySpriteTexture[] array) + static void ClearArray(ref SecondarySpriteTexture[] array) { - Array.Resize(ref array, 0); + array = Array.Empty(); } bool CheckSecondaryTexturesChanged(Sprite sprite) { var changed = CheckSecondaryTexturesChanged(sprite, ref s_TempNewSecondaryTextures); - ClearArray(s_TempNewSecondaryTextures); + ClearArray(ref s_TempNewSecondaryTextures); return changed; } @@ -979,7 +979,7 @@ namespace UnityEngine.UI } else { - ClearArray(newSecondaryTextures); + ClearArray(ref newSecondaryTextures); } // If the list of secondary textures has not changed then return @@ -1017,7 +1017,7 @@ namespace UnityEngine.UI } } - ClearArray(s_TempNewSecondaryTextures); + ClearArray(ref s_TempNewSecondaryTextures); } /// @@ -1925,6 +1925,12 @@ namespace UnityEngine.UI float x = local.x / activeSprite.texture.width; float y = local.y / activeSprite.texture.height; + // Locations outside the image are always considered valid. + // This guarantees that the behavior remains consistent with the case where alphaHitTestMinimumThreshold <= 0. + // Without this check, we would continue to sample a pixel outside the texture. + if (x < 0 || x > 1 || y < 0 || y > 1) + return true; + try { return activeSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold; diff --git a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Slider.cs b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Slider.cs index 99b97371..27c44ec1 100644 --- a/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Slider.cs +++ b/Packages/com.unity.ugui/Runtime/UGUI/UI/Core/Slider.cs @@ -533,6 +533,7 @@ namespace UnityEngine.UI return; m_Value = newValue; + MarkDirty(); UpdateVisuals(); if (sendCallback) { diff --git a/Packages/com.unity.ugui/package.json b/Packages/com.unity.ugui/package.json index fce85ec5..caf198fa 100644 --- a/Packages/com.unity.ugui/package.json +++ b/Packages/com.unity.ugui/package.json @@ -19,5 +19,5 @@ "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0" }, - "_fingerprint": "57cef44123c7486b2e2f08dc6535aecf6c34b8ef" + "_fingerprint": "1a71b488df3ebf0445532ad09fea67fd1a895ab4" } diff --git a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXSlotContainerEditor.cs b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXSlotContainerEditor.cs index d8d93500..8d59a884 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXSlotContainerEditor.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VFXSlotContainerEditor.cs @@ -442,6 +442,7 @@ class VFXSlotContainerEditor : Editor { VFXValueType.Int32, new Color32(125, 110, 191, 255) }, { VFXValueType.Matrix4x4, new Color32(118, 118, 118, 255) }, { VFXValueType.Mesh, new Color32(130, 223, 226, 255) }, + { VFXValueType.SkinnedMeshRenderer, new Color32(130, 223, 226, 255) }, { VFXValueType.None, new Color32(118, 118, 118, 255) }, { VFXValueType.Spline, new Color32(130, 223, 226, 255) }, { VFXValueType.Texture2D, new Color32(250, 137, 137, 255) }, diff --git a/Packages/com.unity.visualeffectgraph/package.json b/Packages/com.unity.visualeffectgraph/package.json index 86b07f92..9207001c 100644 --- a/Packages/com.unity.visualeffectgraph/package.json +++ b/Packages/com.unity.visualeffectgraph/package.json @@ -36,5 +36,5 @@ ] } ], - "_fingerprint": "aecde9dec67d1cb56e53e3135229de90e9d94fb6" + "_fingerprint": "1610c4dd914dcb46d906bfe48b8db559fd045331" }