From 35f56bc781d2a47657f467b46876f5a0614c50ef Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Fri, 22 Aug 2025 10:43:39 +0200 Subject: [PATCH] Auto-sync from SVN revision 64771 --- .../CHANGELOG.md | 13 +- .../Editor/AssemblyInfo.cs | 3 + .../Editor/CoreEditorStyles.cs | 7 +- .../Editor/Debugging/DebugState.cs | 2 +- .../Debugging/DebugUIDrawer.Builtins.cs | 48 +- .../Debugging/DebugUIHandlerCanvasEditor.cs | 2 +- .../Editor/Debugging/DebugWindow.cs | 120 +-- .../Editor/FilterWindow.cs | 2 - .../Editor/Gizmo/HierarchicalSphere.cs | 2 +- .../Editor/HeaderFoldout.cs | 123 +-- .../MemorylessTexture@2x.png | Bin 0 -> 263 bytes .../MemorylessTexture@2x.png.meta | 156 ++++ .../d_MemorylessTexture@2x.png | Bin 0 -> 254 bytes .../d_MemorylessTexture@2x.png.meta | 156 ++++ .../Lighting/CoreLightEditorUtilities.cs | 2 +- .../ProbeVolume/ProbeGIBaking.Invalidation.cs | 2 +- .../ProbeGIBaking.LightTransport.cs | 7 - .../Lighting/ProbeVolume/ProbeGIBaking.cs | 101 ++- .../ProbeVolume/ProbeVolumeBuildProcessor.cs | 9 + .../Lighting/ProbeVolume/ProbeVolumeEditor.cs | 2 +- .../ProbeVolume/ProbeVolumeLightingTab.cs | 22 +- .../Editor/LookDev/CameraController.cs | 2 +- .../Editor/LookDev/CameraState.cs | 7 +- .../LookDev/ComparisonGizmoController.cs | 2 +- .../Editor/LookDev/Stage.cs | 12 +- .../Editor/Properties/AdvancedProperties.cs | 5 +- .../RenderGraphViewer.SidePanel.cs | 8 +- .../Editor/RenderGraph/RenderGraphViewer.cs | 315 +++++++- .../SampleDependencyImporter.cs | 36 +- .../Editor/ScriptTemplates.meta} | 2 +- .../Editor/ScriptTemplates/BlitSRP.txt | 31 + .../Editor/ScriptTemplates/BlitSRP.txt.meta | 7 + .../Editor/ScriptTemplates/ScriptTemplates.cs | 13 + .../ScriptTemplates/ScriptTemplates.cs.meta | 2 + .../Editor/StyleSheets/HeaderFoldout.uss | 103 ++- .../Editor/StyleSheets/HeaderFoldoutDark.uss | 2 +- .../Editor/StyleSheets/HeaderFoldoutLight.uss | 2 +- .../Editor/StyleSheets/RenderGraphViewer.uss | 31 + .../StyleSheets/RenderGraphViewerDark.uss | 34 + .../StyleSheets/RenderGraphViewerLight.uss | 34 + .../Editor/UXML/RenderGraphViewer.uxml | 1 + .../Volume/Drawers/FloatParameterDrawer.cs | 7 +- .../Editor/Volume/VolumeComponentEditor.cs | 22 +- .../Editor/Volume/VolumeParameterDrawer.cs | 10 + .../Editor/Volume/VolumeProfileFactory.cs | 2 +- .../Runtime/AssemblyInfo.cs | 1 + .../Runtime/Camera/CameraSwitcher.cs | 12 +- .../Runtime/Camera/FreeCamera.cs | 6 +- .../Runtime/Common/DynamicArray.cs | 12 +- .../Runtime/Common/ObservableList.cs | 22 +- .../Runtime/Debugging/DebugDisplaySettings.cs | 5 + .../Debugging/DebugDisplaySettingsVolumes.cs | 520 ++++++++---- .../Runtime/Debugging/DebugFrameTiming.cs | 2 - .../Runtime/Debugging/DebugUI.Containers.cs | 7 +- .../Runtime/Debugging/DebugUI.Fields.cs | 58 ++ .../Runtime/Debugging/DebugUI.Panel.cs | 2 +- .../Runtime/Debugging/DebugUI.cs | 11 +- .../Debugging/IDebugDisplaySettingsData.cs | 5 + .../Runtime/Debugging/IVolumeDebugSettings.cs | 3 +- .../Prefabs/Scripts/DebugUIHandlerCanvas.cs | 12 + .../Scripts/DebugUIHandlerContainer.cs | 3 +- .../Prefabs/Scripts/DebugUIHandlerObject.cs | 4 +- .../Scripts/DebugUIHandlerObjectPopupField.cs | 2 +- .../Prefabs/Scripts/DebugUIHandlerRow.cs | 2 +- .../Prefabs/Scripts/DebugUIHandlerWidget.cs | 8 +- .../Runtime/Debugging/VolumeDebugSettings.cs | 6 +- .../Runtime/Documentation.cs | 69 +- .../Runtime/GPUDriven/AssemblyInfo.cs | 1 + .../Debug/DebugDisplayGPUResidentDrawer.cs | 32 +- .../GPUDriven/GPUResidentDrawer.Validator.cs | 2 +- .../Runtime/GPUDriven/GPUResidentDrawer.cs | 43 +- .../Runtime/GPUDriven/InstanceCuller.cs | 609 ++++++++++---- .../Runtime/GPUDriven/InstanceCullerBurst.cs | 9 +- .../GPUDriven/InstanceCullingBatcher.cs | 73 +- .../GPUDriven/InstanceCullingBatcherBurst.cs | 12 +- .../GPUDriven/InstanceData/InstanceData.cs | 164 +++- .../InstanceData/InstanceDataSystem.Jobs.cs | 9 +- .../InstanceData/InstanceDataSystem.cs | 28 +- .../InstanceData/InstanceDataSystemBurst.cs | 14 +- .../Runtime/GPUDriven/LODGroupDataPool.cs | 8 +- ...RenderingUtils.cs => LODRenderingUtils.cs} | 34 +- ...tils.cs.meta => LODRenderingUtils.cs.meta} | 0 .../GPUDriven/RenderersBatchersContext.cs | 14 +- .../ProbeVolume/ProbeAdjustmentVolume.cs | 41 +- .../ProbeAdjustmentVolume.deprecated.cs | 13 + .../ProbeAdjustmentVolume.deprecated.cs.meta | 3 + .../ProbeReferenceVolume.Binding.cs | 4 +- .../ProbeVolume/ProbeReferenceVolume.Debug.cs | 240 +++++- ...eReferenceVolume.ReflProbeNormalization.cs | 29 + .../ProbeVolume/ProbeReferenceVolume.cs | 15 +- .../ProbeVolumeBakingSet.Editor.cs | 24 +- .../ProbeVolumeBakingSetWeakReference.cs | 75 ++ .../ProbeVolumeBakingSetWeakReference.cs.meta | 2 + .../ProbeVolumeBlendStates.compute | 1 - .../ProbeVolume/ProbeVolumeUploadData.compute | 1 - .../ProbeVolumeUploadDataL2.compute | 1 - .../PostProcessing/LensFlareCommonSRP.cs | 19 +- .../Compiler/CompilerContextData.cs | 24 +- .../Compiler/NativePassCompiler.cs | 227 +++--- .../RenderGraph/Compiler/PassesData.cs | 312 ++++---- .../Debug/DebugDisplaySettingsRenderGraph.cs | 17 +- .../Debug/RenderGraphDebugParams.cs | 35 +- .../RenderGraph.ExceptionMessages.cs | 57 ++ .../RenderGraph.ExceptionMessages.cs.meta | 2 + .../Runtime/RenderGraph/RenderGraph.cs | 355 ++++++++- .../Runtime/RenderGraph/RenderGraphBuilder.cs | 1 + .../RenderGraph/RenderGraphBuilders.cs | 8 +- .../RenderGraphCompilationCache.cs | 2 +- .../RenderGraphDefaultResources.cs | 11 +- .../RenderGraph/RenderGraphGlobalSettings.cs | 6 +- .../Runtime/RenderGraph/RenderGraphLogger.cs | 14 +- .../Runtime/RenderGraph/RenderGraphPass.cs | 12 +- .../RenderGraphResourceRegistry.cs | 55 +- .../RenderGraph/RenderGraphResourceTexture.cs | 18 +- .../Settings/LightmapSamplingSettings.cs | 2 + .../RenderingDebuggerRuntimeResources.cs | 24 + .../RenderingDebuggerRuntimeResources.cs.meta | 2 + .../Runtime/Utilities/CoreUtils.cs | 20 +- .../Runtime/Volume/Volume.cs | 45 +- .../Runtime/Volume/VolumeComponent.cs | 36 +- .../Runtime/Volume/VolumeManager.cs | 48 +- .../Runtime/Volume/VolumeParameter.cs | 14 +- .../Runtime/Volume/VolumeProfile.cs | 3 +- .../Runtime/XR/XRGraphicsAutomatedTests.cs | 2 +- .../Runtime/XR/XRPass.cs | 57 ++ .../Runtime/XR/XRSRPSettings.cs | 22 + .../Runtime/XR/XRSystem.cs | 29 +- .../Runtime/XR/XRView.cs | 4 +- .../Runtime/XR/XRVisibleMesh.cs | 162 ++++ .../Runtime/XR/XRVisibleMesh.cs.meta | 2 + .../ShaderLibrary/API/GLCore.hlsl | 6 +- .../ShaderLibrary/API/GLES3.hlsl | 6 +- .../ShaderLibrary/Common.hlsl | 4 +- .../ShaderLibrary/HDROutput.hlsl | 33 +- .../ShaderLibrary/SphericalHarmonics.hlsl | 1 + .../ShaderLibrary/TextureXR.hlsl | 6 +- .../Tests/Editor/CopyDepthToBuffer.compute | 20 + .../Editor/CopyDepthToBuffer.compute.meta | 7 + .../Editor/Debugging/VolumePanelTests.cs | 51 ++ .../Editor/Debugging/VolumePanelTests.cs.meta | 2 + .../Tests/Editor/DynamicArrayTests.cs | 19 + .../GPUDriven/GPUDrivenRenderingTests.cs | 15 +- .../Editor/RemoveRange.Extensions.Tests.cs | 5 +- .../Editor/RenderGraph.ComputeGraphHash.cs | 98 +-- .../Tests/Editor/RenderGraphTests.cs | 741 ++++++++++++++---- .../Tests/Editor/ScriptTemplateTests.cs | 25 + .../Tests/Editor/ScriptTemplateTests.cs.meta | 2 + .../Editor/Utilities/ObservableListTests.cs | 399 ++++++++++ .../Utilities/ObservableListTests.cs.meta | 3 + .../Tests/Runtime/ObservableListTests.cs | 20 - .../Tests/Runtime/ObservableListTests.cs.meta | 11 - .../Tests/Runtime/RuntimeExampleTest.cs | 1 + .../Tests/Runtime/RuntimeProfilerTests.cs | 5 +- .../Tests/Runtime/Threading/FunctionTests.cs | 9 + .../package.json | 6 +- .../CHANGELOG.md | 2 +- .../package.json | 8 +- .../CHANGELOG.md | 14 +- .../Lighting/Reflection/HDProbeUI.Skin.cs | 8 +- .../HDScreenSpaceReflectionEditor.cs | 5 + .../ShaderGraph/VoxelizationTransforms.hlsl | 2 +- .../Material/LayeredLit/LayeredLitGUI.cs | 16 +- .../ShaderGraph/HDSixWaySubTarget.cs | 4 +- .../ShaderGraph/ShaderPass.template.hlsl | 15 +- .../Editor/Material/SixWayLit/SixWayGUI.cs | 2 +- .../Material/UIBlocks/ShaderGraphUIBlock.cs | 4 +- .../Material/UIBlocks/SurfaceOptionUIBlock.cs | 2 +- .../Editor/RenderPipeline/HDEditorUtils.cs | 23 +- .../RenderPipeline/HDRenderPipelineUI.Skin.cs | 1 - .../RenderPipeline/HDRenderPipelineUI.cs | 2 - .../Editor/USS/FrameSettings.uss | 16 + .../Shaders/VFXVertexProbeSampling.template | 2 +- .../VFXGraph/UIBlocks/VFXShaderGraphGUI.cs | 3 +- .../Editor/Wizard/HDWizard.UIElement.cs | 2 +- .../Editor/Wizard/HDWizard.Window.cs | 5 +- .../Editor/Wizard/USS/Wizard.uss | 17 + .../Runtime/Debug/DebugDisplay.cs | 170 ++-- .../Debug/DebugDisplaySettingsCamera.cs | 213 +++++ .../Debug/DebugDisplaySettingsCamera.cs.meta | 2 + .../Debug/DebugDisplaySettingsDecal.cs | 22 +- .../Runtime/Debug/HDDebugDisplaySettings.cs | 5 +- .../Runtime/Debug/HDDebugDisplayStats.cs | 1 - .../Runtime/Debug/HDVolumeDebugSettings.cs | 2 + .../Runtime/Debug/NVIDIADebugView.cs | 21 +- .../Runtime/Documentation.cs | 5 + .../Runtime/Lighting/GlobalIllumination.cs | 2 +- .../Lighting/Light/HDAdditionalLightData.cs | 1 + .../Lighting/LightLoop/Deferred.compute | 2 +- .../LightLoop/ShaderVariablesLightLoop.hlsl | 2 +- .../Lighting/LightLoop/lightlistbuild.compute | 59 +- .../Lighting/LightLoop/materialflags.compute | 2 +- .../Runtime/Lighting/Reflection/HDProbe.cs | 4 +- .../ScreenSpaceGlobalIllumination.compute | 2 +- .../ScreenSpaceReflection.cs | 7 + .../ScreenSpaceReflections.compute | 2 +- .../HDRenderPipeline.VolumetricLighting.cs | 9 +- ...DRenderPipeline.VolumetricLighting.cs.hlsl | 2 +- .../VolumetricLighting.compute | 9 +- .../Runtime/Material/AxF/AxF.shader | 2 +- .../Material/LayeredLit/LayeredLit.shader | 4 +- .../LayeredLit/LayeredLitTessellation.shader | 4 +- .../Runtime/Material/Lit/Lit.shader | 6 +- .../Runtime/Material/Lit/LitDecalData.hlsl | 1 + .../Material/Lit/LitTessellation.shader | 6 +- .../Runtime/Material/MaterialExtension.cs | 6 +- .../Material/MaterialExternalReferences.cs | 3 + .../Material/SixWayLit/SixWaySmokeLit.cs | 8 +- .../Material/SixWayLit/SixWaySmokeLit.cs.hlsl | 40 +- .../Material/SixWayLit/SixWaySmokeLit.hlsl | 19 +- .../Material/TerrainLit/TerrainLit.shader | 4 +- .../TerrainLit/TerrainLit_Basemap.shader | 4 +- .../Shaders/CompositeWithUIAndOETF.shader | 12 +- .../Shaders/MotionBlurMergeTilePass.compute | 2 +- .../Shaders/TemporalAntiAliasing.shader | 2 +- .../Camera/HDAdditionalCameraData.cs | 70 -- .../Runtime/RenderPipeline/Camera/HDCamera.cs | 8 + .../RenderPipeline/HDRenderPipeline.Debug.cs | 5 +- .../HDRenderPipeline.RenderGraph.cs | 14 +- .../RenderPipeline/HDRenderPipeline.cs | 55 +- ...DRenderPipelineGlobalSettings.Migration.cs | 3 +- .../HDRaytracingManager.HDRTASManager.cs | 2 +- .../Raytracing/HDRaytracingManager.cs | 10 +- ...derPipeline.RaytracingRecursiveRenderer.cs | 10 +- .../HDRenderPipeline.RaytracingReflection.cs | 4 + .../Shaders/Denoising/BilateralFilter.hlsl | 2 +- .../ReBlur/ReBlur_BilateralUtilities.hlsl | 2 +- .../Denoising/ReBlur/ReBlur_Blur.compute | 2 +- .../ReBlur/ReBlur_CopyHistory.compute | 2 +- .../ReBlur/ReBlur_HistoryFix.compute | 2 +- .../Denoising/ReBlur/ReBlur_PostBlur.compute | 2 +- .../ReBlur_TemporalAccumulation.compute | 2 +- .../ReBlur_TemporalStabilization.compute | 4 +- .../Shaders/Denoising/TemporalFilter.compute | 4 +- .../RayTracingIndirectDiffuse.hlsl | 2 +- .../RaytracingIndirectDiffuse.compute | 2 +- .../Raytracing/Shaders/RayMarching.compute | 2 +- .../Shaders/RayTracingSubSurface.raytrace | 2 +- .../RaytracingAmbientOcclusion.raytrace | 2 +- .../RaytracingReflectionFilter.compute | 2 +- .../Reflections/RaytracingReflections.compute | 2 +- .../RaytracingReflections.raytrace | 2 +- .../Shaders/Shadows/RaytracingShadow.compute | 2 +- .../RenderPass/CustomPass/CustomPass.cs | 10 + .../CustomPass/CustomPassContext.cs | 7 +- .../CustomPass/CustomPassInjectionPoint.cs | 2 + .../CustomPassInjectionPoint.cs.hlsl | 1 + .../Settings/FrameSettingsHistory.cs | 45 +- .../ResolveStencilBuffer.compute | 2 +- .../Runtime/Tools/ColorCheckerTool.cs | 3 +- .../Runtime/VFXGraph/Shaders/VFXLit.hlsl | 18 +- .../Water/Shaders/UnderWaterUtilities.hlsl | 2 +- .../Runtime/Water/Shaders/WaterLine.compute | 2 +- .../package.json | 14 +- .../UnifiedRayTracing/AccelStructTests.cs | 4 +- .../package.json | 2 +- Packages/com.unity.shadergraph/CHANGELOG.md | 23 +- .../Data/Graphs/AbstractShaderProperty.cs | 41 +- .../Editor/Data/Graphs/GraphData.cs | 2 +- .../Editor/Data/Graphs/ShaderKeyword.cs | 20 +- .../Data/Graphs/Vector1ShaderProperty.cs | 47 +- .../Data/Graphs/VectorShaderProperty.cs | 2 +- .../Editor/Data/Implementation/NodeUtils.cs | 2 +- .../Data/Nodes/Channel/AppendVectorNode.cs | 184 +++++ .../Nodes/Channel/AppendVectorNode.cs.meta | 2 + .../Data/Nodes/Math/Advanced/PosterizeNode.cs | 2 +- .../Nodes/Math/Vector/FresnelEffectNode.cs | 2 +- .../Nodes/Math/Vector/RotateAboutAxisNode.cs | 29 +- .../Editor/Data/Nodes/UV/RotateNode.cs | 44 +- .../Editor/Data/Nodes/Utility/KeywordNode.cs | 22 +- .../Editor/Data/Util/KeywordCollector.cs | 12 +- .../Editor/Data/Util/KeywordUtil.cs | 2 + .../Editor/Drawing/Inspector/InspectorView.cs | 27 +- .../PropertyDrawers/IntegerPropertyDrawer.cs | 4 +- .../ShaderInputPropertyDrawer.cs | 529 ++++++++++++- .../Drawing/Inspector/TabbedView/TabButton.cs | 140 ---- .../Inspector/TabbedView/TabButton.cs.meta | 11 - .../Inspector/TabbedView/TabbedView.cs | 153 ---- .../Inspector/TabbedView/TabbedView.cs.meta | 11 - .../ShaderGraphPropertyDrawers.cs | 18 +- .../Editor/Drawing/Views/MaterialGraphView.cs | 2 + .../Enumerations/KeywordDefinition.cs | 5 +- .../Editor/Generation/Processors/Generator.cs | 3 + .../Resources/DefaultHeatmapValues.asset | 2 + .../Editor/Resources/Styles/InspectorView.uss | 19 +- .../Editor/Resources/Styles/SGBlackboard.uss | 2 +- .../Resources/Styles/TabButtonStyles.uss | 42 - .../Resources/Styles/TabButtonStyles.uss.meta | 11 - .../Editor/Resources/Styles/TabbedView.uss | 15 - .../Resources/Styles/TabbedView.uss.meta | 11 - .../Editor/Resources/UXML/GraphInspector.uxml | 18 +- .../Editor/Resources/UXML/TabButton.uxml | 9 - .../Editor/Resources/UXML/TabButton.uxml.meta | 10 - .../Editor/ShaderGraphPreferences.cs | 6 +- .../Editor/ShaderGraphProjectSettings.cs | 29 +- .../Tests/Editor/UnitTests/UtilityTests.cs | 44 +- Packages/com.unity.shadergraph/package.json | 13 +- .../Editor/TMP/TMPro_EditorShaderUtilities.cs | 14 +- .../UGUI/EventSystem/EventSystemEditor.cs | 7 + .../Runtime/TMP/TMP_InputField.cs | 1 + .../Runtime/UGUI/AssemblyInfo.cs | 4 + .../Runtime/UGUI/AssemblyInfo.cs.meta | 2 + .../Runtime/UGUI/EventSystem/EventSystem.cs | 150 ++-- .../Runtime/UGUI/EventSystem/RaycastResult.cs | 31 + .../UIElements/PanelEventHandler.cs | 125 ++- .../EventSystem/UIElements/PanelRaycaster.cs | 34 +- .../UIToolkitInteroperabilityBridge.cs | 365 +++++++++ .../UIToolkitInteroperabilityBridge.cs.meta | 2 + .../UIElements/WorldDocumentRaycaster.cs | 118 +++ .../UIElements/WorldDocumentRaycaster.cs.meta | 2 + .../Runtime/UGUI/Dropdown/DropdownTests.cs | 2 +- .../UGUI/InputField/TouchInputFieldTests.cs | 23 +- Packages/com.unity.ugui/package.json | 2 +- .../com.unity.visualeffectgraph/CHANGELOG.md | 18 +- .../Editor/Compiler/VFXGraphCompiledData.cs | 10 +- .../Editor/Data/VFXDataParticle.cs | 36 +- .../GraphView/Views/VFXConvertSubgraph.cs | 5 +- .../Editor/GraphView/Views/VFXView.cs | 10 +- .../Inspector/AdvancedVisualEffectEditor.cs | 9 +- .../Editor/Inspector/VFXAssetEditor.cs | 21 +- .../Implementations/VFXStaticMeshOutput.cs | 27 +- .../Templates/VFXConfig.template.hlsl | 2 +- .../VFXConfigPlanarPrimitive.template.hlsl | 2 +- .../CreateFromTemplateDropDownButton.cs | 24 +- .../TemplateWindow/VFXTemplateDescriptor.cs | 48 -- .../VFXTemplateDescriptor.cs.meta | 11 - .../TemplateWindow/VFXTemplateHelper.cs | 90 ++- .../TemplateWindow/VFXTemplateHelper.cs.meta | 12 +- .../VFXTemplateHelperInternal.cs | 114 +++ .../VFXTemplateHelperInternal.cs.meta | 3 + .../TemplateWindow/VFXTemplateWindow.cs | 489 ------------ .../TemplateWindow/VFXTemplateWindow.cs.meta | 11 - .../Editor/UIResources/uss/VFXStickynote.uss | 34 + .../UIResources/uss/VFXTemplateWindow.uss | 180 ----- .../uss/VFXTemplateWindow.uss.meta | 11 - .../UIResources/uxml/VFXTemplateItem.uxml | 10 - .../uxml/VFXTemplateItem.uxml.meta | 10 - .../UIResources/uxml/VFXTemplateSection.uxml | 10 - .../uxml/VFXTemplateSection.uxml.meta | 10 - .../UIResources/uxml/VFXTemplateWindow.uxml | 46 -- .../uxml/VFXTemplateWindow.uxml.meta | 10 - .../Unity.VisualEffectGraph.Editor.asmdef | 4 +- .../Editor/VFXAssetEditorUtility.cs | 8 +- .../Shaders/ParticleMeshes/Pass.template | 2 +- .../ParticlePlanarPrimitives/Pass.template | 2 +- .../Shaders/VFXParticleCommon.template | 2 +- .../com.unity.visualeffectgraph/package.json | 10 +- 346 files changed, 8183 insertions(+), 3597 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png.meta rename Packages/{com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView.meta => com.unity.render-pipelines.core/Editor/ScriptTemplates.meta} (77%) create mode 100644 Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt create mode 100644 Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs.meta rename Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/{LODGroupRenderingUtils.cs => LODRenderingUtils.cs} (69%) rename Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/{LODGroupRenderingUtils.cs.meta => LODRenderingUtils.cs.meta} (100%) create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute.meta create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs.meta delete mode 100644 Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs delete mode 100644 Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs.meta create mode 100644 Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs create mode 100644 Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs create mode 100644 Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs.meta delete mode 100644 Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView/TabButton.cs delete mode 100644 Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView/TabButton.cs.meta delete mode 100644 Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView/TabbedView.cs delete mode 100644 Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView/TabbedView.cs.meta delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/Styles/TabButtonStyles.uss delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/Styles/TabButtonStyles.uss.meta delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/Styles/TabbedView.uss delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/Styles/TabbedView.uss.meta delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/UXML/TabButton.uxml delete mode 100644 Packages/com.unity.shadergraph/Editor/Resources/UXML/TabButton.uxml.meta create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/AssemblyInfo.cs create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/AssemblyInfo.cs.meta create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/UIToolkitInteroperabilityBridge.cs create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/UIToolkitInteroperabilityBridge.cs.meta create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/WorldDocumentRaycaster.cs create mode 100644 Packages/com.unity.ugui/Runtime/UGUI/EventSystem/UIElements/WorldDocumentRaycaster.cs.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateDescriptor.cs delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateDescriptor.cs.meta create mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateHelperInternal.cs create mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateHelperInternal.cs.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateWindow.cs delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/TemplateWindow/VFXTemplateWindow.cs.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uss/VFXTemplateWindow.uss delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uss/VFXTemplateWindow.uss.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateItem.uxml delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateItem.uxml.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateSection.uxml delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateSection.uxml.meta delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateWindow.uxml delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/UIResources/uxml/VFXTemplateWindow.uxml.meta diff --git a/Packages/com.unity.render-pipelines.core/CHANGELOG.md b/Packages/com.unity.render-pipelines.core/CHANGELOG.md index 0e7d310e..97d1d7ae 100644 --- a/Packages/com.unity.render-pipelines.core/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.core/CHANGELOG.md @@ -12,7 +12,7 @@ The version number for this package has increased due to a version update of a r ## [17.0.3] - 2025-02-13 -This version is compatible with Unity 6000.2.0a1. +This version is compatible with Unity 6000.2.0a5. ### Added - Added Variable Rate Shading API support for (Raster)CommandBuffer(s), RenderGraph and RTHandles. @@ -20,6 +20,10 @@ Various VRS utilities. - helper functions to Render Graph. ### Changed +- Modified the Rendering Debugger to prevent resource transfers in retail builds. +- Rendering Debugger - Moved the GPU Resident Drawer to the Rendering Section. +- Rendering Debugger - Moved Render Graph to the Rendering Section. +- Added an API to query the preferred depth-only format for target platforms. - Improved Depth usage performance for some platforms. - Improved the Native Render Pass CPU performance by implementing a Render Pass pooling system (URP RG). - Reworked the additional properties. @@ -30,6 +34,13 @@ Various VRS utilities. - Added What's New in Unity 6 to SRP Core Package. ### Fixed +- Fixed an issue in Render Graph Viewer where text would overlap after searching in the Pass List. +- Fix pass culling corner case where resources are never deallocated when the last pass using them is culled +- Fix RenderGraphObjectPool and GetTempMaterialPropertyBlock() usage in URP RenderGraph +- Fix async compute corner case where URP RenderGraph was waiting for a resource not written by any pass +- Serialization errors are thrown when "com.unity.render-pipelines.core" is added as a custom package +- Add missing check for count parameter in DynamicArray.FindIndex +- Fixed incorrect format of default shadow texture - Fixed render graph incorrectly handling rendering to array slices and mipmaps other than 0 in some cases. - Fixed an issue where Lens Flare was not rendering properly in OpenGLES3. - Fixed missing STP shaders & visual artifacts when targeting GLCore renderer. diff --git a/Packages/com.unity.render-pipelines.core/Editor/AssemblyInfo.cs b/Packages/com.unity.render-pipelines.core/Editor/AssemblyInfo.cs index e8677799..da38b033 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/AssemblyInfo.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/AssemblyInfo.cs @@ -3,3 +3,6 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Shared")] [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Tests")] [assembly: InternalsVisibleTo("Unity.RenderPipelines.HighDefinition.Editor.Tests")] +[assembly: InternalsVisibleTo("Unity.RenderPipelines.HighDefinition.Editor.Tests")] +[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")] + diff --git a/Packages/com.unity.render-pipelines.core/Editor/CoreEditorStyles.cs b/Packages/com.unity.render-pipelines.core/Editor/CoreEditorStyles.cs index 74af19d2..45fcdc57 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/CoreEditorStyles.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/CoreEditorStyles.cs @@ -118,6 +118,8 @@ namespace UnityEditor.Rendering /// Warning icon public static readonly Texture2D iconWarn; + /// Info icon + public static readonly Texture2D iconInfo; /// Help icon public static readonly Texture2D iconHelp; /// Fail icon @@ -144,7 +146,7 @@ namespace UnityEditor.Rendering case MessageType.None: return null; case MessageType.Info: - return iconHelp; + return iconInfo; case MessageType.Warning: return iconWarn; case MessageType.Error: @@ -215,7 +217,8 @@ namespace UnityEditor.Rendering greenTexture = CoreEditorUtils.CreateColoredTexture2D(Color.green, "Green 1x1"); blueTexture = CoreEditorUtils.CreateColoredTexture2D(Color.blue, "Blue 1x1"); - iconHelp = CoreEditorUtils.FindTexture("_Help"); + iconHelp = CoreEditorUtils.LoadIcon("icons", "_Help", ".png"); + iconInfo = CoreEditorUtils.LoadIcon("icons", "console.infoicon", ".png"); iconWarn = CoreEditorUtils.LoadIcon("icons", "console.warnicon", ".png"); iconFail = CoreEditorUtils.LoadIcon("icons", "console.erroricon", ".png"); iconSuccess = EditorGUIUtility.FindTexture("TestPassed"); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs index 5a57ad95..2e72da47 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs @@ -179,7 +179,7 @@ namespace UnityEditor.Rendering /// /// Object Debug State. /// - [Serializable, DebugState(typeof(DebugUI.ObjectPopupField))] + [Serializable, DebugState(typeof(DebugUI.ObjectPopupField), typeof(DebugUI.CameraSelector), typeof(DebugUI.ObjectField))] public sealed class DebugStateObject : DebugState { /// diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs index ca52e10e..1236c047 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs @@ -292,14 +292,40 @@ namespace UnityEditor.Rendering rect = EditorGUI.PrefixLabel(rect, label); var elements = field.getObjects(); - if (elements?.Any() ?? false) + var count = elements != null ? elements.Count() : -1; + if (count > 0) // Check if elements are not null and have any items { - var elementsArrayNames = elements.Select(e => e.name).ToArray(); - var elementsArrayIndices = Enumerable.Range(0, elementsArrayNames.Length).ToArray(); - var selectedIndex = selectedValue != null ? Array.IndexOf(elementsArrayNames, selectedValue.name) : 0; - var newSelectedIndex = EditorGUI.IntPopup(rect, selectedIndex, elementsArrayNames, elementsArrayIndices); + // Initialize arrays for names and indices, with +1 for the "None" option + string[] elementsArrayNames = new string[count + 1]; // +1 for the "None" option + int[] elementsArrayIndices = new int[elementsArrayNames.Length]; // Same size as elementsArrayNames + + // Add the "None" option at the beginning + elementsArrayNames[0] = "None"; + elementsArrayIndices[0] = 0; // "None" corresponds to index 0 + + // Populate the rest of the arrays with the element names and indices + int index = 1; + foreach (var element in elements) + { + elementsArrayNames[index] = element.name; + elementsArrayIndices[index] = index; // Set the index to match the element's position + index++; + } + + // Determine the selected index + int selectedIndex = selectedValue != null + ? Array.IndexOf(elementsArrayNames, selectedValue.name) + : 0; + + // Show the dropdown and get the new selected index + int newSelectedIndex = EditorGUI.IntPopup(rect, selectedIndex, elementsArrayNames, elementsArrayIndices); + + // If the selected index changed, update selectedValue if (selectedIndex != newSelectedIndex) - selectedValue = elements.ElementAt(newSelectedIndex); + { + // If "None" is selected, set selectedValue to null + selectedValue = newSelectedIndex == 0 ? null : elements.ElementAt(newSelectedIndex - 1); + } } else { @@ -451,6 +477,8 @@ namespace UnityEditor.Rendering /// Debug State associated with the Debug Item. public override void Begin(DebugUI.Widget widget, DebugState state) { + CoreEditorUtils.DrawSplitter(); + var w = Cast(widget); var s = Cast(state); @@ -458,7 +486,7 @@ namespace UnityEditor.Rendering Action fillContextMenuAction = null; - if (w.contextMenuItems != null) + if (w.contextMenuItems is { Count: > 0 }) { fillContextMenuAction = menu => { @@ -469,8 +497,8 @@ namespace UnityEditor.Rendering }; } - bool previousValue = (bool)w.GetValue(); - bool value = CoreEditorUtils.DrawHeaderFoldout(title, previousValue, isTitleHeader: w.isHeader, customMenuContextAction: fillContextMenuAction); + bool previousValue = w.GetValue(); + bool value = CoreEditorUtils.DrawHeaderFoldout(title, previousValue, isTitleHeader: w.isHeader, customMenuContextAction: fillContextMenuAction, documentationURL: w.documentationUrl); if (previousValue != value) Apply(w, s, value); @@ -827,7 +855,7 @@ namespace UnityEditor.Rendering bool isAlternate = r % 2 == 0; - EditorGUI.LabelField(rowRect, GUIContent.none, EditorGUIUtility.TrTextContent(row.displayName),isAlternate ? DebugWindow.Styles.centeredLeft : DebugWindow.Styles.centeredLeftAlternate); + EditorGUI.LabelField(rowRect, GUIContent.none, EditorGUIUtility.TrTextContent(row.displayName), isAlternate ? DebugWindow.Styles.centeredLeft : DebugWindow.Styles.centeredLeftAlternate); rowRect.xMin -= 2; rowRect.xMax += 2; diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIHandlerCanvasEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIHandlerCanvasEditor.cs index 5e2c2b21..dc3b0b25 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIHandlerCanvasEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIHandlerCanvasEditor.cs @@ -60,7 +60,7 @@ namespace UnityEngine.Rendering.UI { var prefab = list.serializedProperty.GetArrayElementAtIndex(list.index).FindPropertyRelative("prefab").objectReferenceValue as GameObject; if (prefab) - EditorGUIUtility.PingObject(prefab.gameObject); + EditorGUIUtility.PingObject(prefab); } }; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs index 9547e9e6..625821b9 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs @@ -132,6 +132,7 @@ namespace UnityEditor.Rendering { var window = GetWindow(); window.titleContent = Styles.windowTitle; + window.minSize = new Vector2(800f, 300f); } [MenuItem("Window/Analysis/Rendering Debugger", validate = true)] @@ -262,6 +263,32 @@ namespace UnityEditor.Rendering UpdateWidgetStates(panel); } + DebugState GetOrCreateDebugStateForValueField(DebugUI.Widget widget) + { + // Skip runtime & readonly only items + if (widget.isInactiveInEditor) + return null; + + if (widget is not DebugUI.IValueField valueField) + return null; + + string queryPath = widget.queryPath; + if (!m_WidgetStates.TryGetValue(queryPath, out var state) || state == null) + { + var widgetType = widget.GetType(); + if (s_WidgetStateMap.TryGetValue(widgetType, out Type stateType)) + { + Assert.IsNotNull(stateType); + state = (DebugState)CreateInstance(stateType); + state.queryPath = queryPath; + state.SetValue(valueField.GetValue(), valueField); + m_WidgetStates[queryPath] = state; + } + } + + return state; + } + void UpdateWidgetStates(DebugUI.IContainer container) { // Skip runtime only containers, we won't draw them so no need to serialize them either @@ -273,26 +300,10 @@ namespace UnityEditor.Rendering { // Skip non-serializable widgets but still traverse them in case one of their // children needs serialization support - if (widget is DebugUI.IValueField valueField) - { - // Skip runtime & readonly only items - if (widget.isInactiveInEditor) - return; + var state = GetOrCreateDebugStateForValueField(widget); - string guid = widget.queryPath; - if (!m_WidgetStates.TryGetValue(guid, out var state) || state == null) - { - var widgetType = widget.GetType(); - if (s_WidgetStateMap.TryGetValue(widgetType, out Type stateType)) - { - Assert.IsNotNull(stateType); - var inst = (DebugState)CreateInstance(stateType); - inst.queryPath = guid; - inst.SetValue(valueField.GetValue(), valueField); - m_WidgetStates[guid] = inst; - } - } - } + if (state != null) + continue; // Recurse if the widget is a container if (widget is DebugUI.IContainer containerField) @@ -302,22 +313,27 @@ namespace UnityEditor.Rendering public void ApplyStates(bool forceApplyAll = false) { + // If we are in playmode, and the runtime UI is shown, avoid that the editor UI + // applies the data of the internal debug states, as they are not kept in sync + if (Application.isPlaying && DebugManager.instance.displayRuntimeUI) + return; + if (!forceApplyAll && DebugState.m_CurrentDirtyState != null) { ApplyState(DebugState.m_CurrentDirtyState.queryPath, DebugState.m_CurrentDirtyState); - DebugState.m_CurrentDirtyState = null; - return; } - - foreach (var state in m_WidgetStates) - ApplyState(state.Key, state.Value); + else + { + foreach (var state in m_WidgetStates) + ApplyState(state.Key, state.Value); + } DebugState.m_CurrentDirtyState = null; } void ApplyState(string queryPath, DebugState state) { - if (!(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget)) + if (state == null || !(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget)) return; widget.SetValue(state.GetValue()); @@ -372,6 +388,8 @@ namespace UnityEditor.Rendering UpdateWidgetStates(); ApplyStates(); m_IsDirty = false; + + Repaint(); } } @@ -392,16 +410,6 @@ namespace UnityEditor.Rendering return; } - // Background color - var wrect = position; - wrect.x = 0; - wrect.y = 0; - var oldColor = GUI.color; - GUI.color = s_Styles.skinBackgroundColor; - GUI.DrawTexture(wrect, EditorGUIUtility.whiteTexture); - GUI.color = oldColor; - - GUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.FlexibleSpace(); if (GUILayout.Button(Styles.resetButtonContent, EditorStyles.toolbarButton)) @@ -496,8 +504,14 @@ namespace UnityEditor.Rendering using (var scrollScope = new EditorGUILayout.ScrollViewScope(m_ContentScroll)) { + const float scrollViewTopMargin = 4f; + GUILayout.Space(scrollViewTopMargin); + TraverseContainerGUI(selectedPanel); m_ContentScroll = scrollScope.scrollPosition; + + const float scrollViewBottomMargin = 10f; + GUILayout.Space(scrollViewBottomMargin); } } @@ -549,17 +563,25 @@ namespace UnityEditor.Rendering Debug.LogError($"Widget {widget.GetType()} query path is null"); return; } - // State will be null for stateless widget - m_WidgetStates.TryGetValue(widget.queryPath, out DebugState state); - - GUILayout.Space(4); if (!s_WidgetDrawerMap.TryGetValue(widget.GetType(), out DebugUIDrawer drawer)) { - EditorGUILayout.LabelField("Drawer not found (" + widget.GetType() + ")."); + foreach (var pair in s_WidgetDrawerMap) + { + if (pair.Key.IsAssignableFrom(widget.GetType())) + { + drawer = pair.Value; + break; + } + } } + + if (drawer == null) + EditorGUILayout.LabelField("Drawer not found (" + widget.GetType() + ")."); else { + var state = GetOrCreateDebugStateForValueField(widget); + drawer.Begin(widget, state); if (drawer.OnGUI(widget, state)) @@ -608,8 +630,6 @@ namespace UnityEditor.Rendering public readonly GUIStyle sectionScrollView = "PreferencesSectionBox"; public readonly GUIStyle sectionElement = new GUIStyle("PreferencesSection"); public readonly GUIStyle selected = "OL SelectedRow"; - public readonly GUIStyle sectionHeader = new GUIStyle(EditorStyles.largeLabel); - public readonly Color skinBackgroundColor; public static GUIStyle centeredLeft = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleLeft }; public static GUIStyle centeredLeftAlternate = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleLeft }; @@ -619,15 +639,10 @@ namespace UnityEditor.Rendering public Styles() { - Color textColorDarkSkin = new Color32(210, 210, 210, 255); - Color textColorLightSkin = new Color32(102, 102, 102, 255); - Color backgroundColorDarkSkin = new Color32(38, 38, 38, 128); - Color backgroundColorLightSkin = new Color32(128, 128, 128, 96); - centeredLeftAlternate.normal.background = CoreEditorUtils.CreateColoredTexture2D( EditorGUIUtility.isProSkin ? new Color(63 / 255.0f, 63 / 255.0f, 63 / 255.0f, 255 / 255.0f) - : new Color(202 / 255.0f, 202 / 255.0f, 202 / 255.0f, 255 / 255.0f), + : new Color(211 / 255.0f, 211 / 255.0f, 211 / 255.0f, 211 / 255.0f), "centeredLeftAlternate Background"); sectionScrollView = new GUIStyle(sectionScrollView); @@ -635,19 +650,12 @@ namespace UnityEditor.Rendering sectionElement.alignment = TextAnchor.MiddleLeft; - sectionHeader.fontStyle = FontStyle.Bold; - sectionHeader.fontSize = 18; - sectionHeader.margin.top = 10; - sectionHeader.margin.left += 1; - sectionHeader.normal.textColor = EditorGUIUtility.isProSkin ? textColorDarkSkin : textColorLightSkin; - skinBackgroundColor = EditorGUIUtility.isProSkin ? backgroundColorDarkSkin : backgroundColorLightSkin; - labelWithZeroValueStyle.normal.textColor = Color.gray; // Make sure that textures are unloaded on domain reloads. void OnBeforeAssemblyReload() { - UnityEngine.Object.DestroyImmediate(centeredLeftAlternate.normal.background); + DestroyImmediate(centeredLeftAlternate.normal.background); AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs b/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs index 3be64f05..f765de2f 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs @@ -232,8 +232,6 @@ namespace UnityEditor.Rendering s_FilterWindow = null; } - void OnLostFocus() => Close(); - internal static bool ValidateAddComponentMenuItem() { return true; diff --git a/Packages/com.unity.render-pipelines.core/Editor/Gizmo/HierarchicalSphere.cs b/Packages/com.unity.render-pipelines.core/Editor/Gizmo/HierarchicalSphere.cs index 5aabac07..f5446f55 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Gizmo/HierarchicalSphere.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Gizmo/HierarchicalSphere.cs @@ -128,7 +128,7 @@ namespace UnityEditor.Rendering if (filled) { material.SetPass(0); - Matrix4x4 drawMatrix = Matrix4x4.TRS((Vector3)Handles.matrix.GetColumn(3), Quaternion.identity, Vector3.one * radius * 2f); + Matrix4x4 drawMatrix = Matrix4x4.TRS((Vector3)Handles.matrix.GetColumn(3), Quaternion.identity, 2f * radius * Vector3.one); Graphics.DrawMeshNow(k_MeshSphere, drawMatrix); } diff --git a/Packages/com.unity.render-pipelines.core/Editor/HeaderFoldout.cs b/Packages/com.unity.render-pipelines.core/Editor/HeaderFoldout.cs index ecf57e7d..73dc932d 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/HeaderFoldout.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/HeaderFoldout.cs @@ -9,8 +9,12 @@ namespace UnityEditor.Rendering public partial class HeaderFoldout : Foldout { const string k_StylesheetPathFormat = "Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldout{0}.uss"; - const string k_Class = "header-foldout"; - const string k_IconName = "header-foldout__icon"; + const string k_MainClass = "header-foldout"; + const string k_EnableClass = k_MainClass + "__enable"; + const string k_IconClass = k_MainClass + "__icon"; + const string k_LabelClass = k_MainClass + "__label"; + const string k_HelpButtonClass = k_MainClass + "__help-button"; + const string k_ContextButtonClass = k_MainClass + "__context-button"; private string m_DocumentationURL; private Texture2D m_Icon; @@ -18,6 +22,8 @@ namespace UnityEditor.Rendering private VisualElement m_HelpButton; private VisualElement m_ContextMenuButton; private VisualElement m_IconElement; + private Toggle m_Toggle; + private Label m_Text; /// URL to use on documentation icon. If null, button don't show. public string documentationURL @@ -61,51 +67,91 @@ namespace UnityEditor.Rendering m_IconElement.style.display = m_Icon != null ? DisplayStyle.Flex : DisplayStyle.None; } } + + /// Property to get the enablement state + public bool enabled + { + get => m_Toggle.value; + set => m_Toggle.value = value; + } + + /// Property to get the enablement visibility state + public bool showEnableCheckbox + { + get => m_Toggle.style.display == DisplayStyle.Flex; + set => m_Toggle.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; + } + + /// Quick access to the enable toggle if one need to register events + public Toggle enableToggle => m_Toggle; + + /// Property to get the title + public new string text + { + get => m_Text.text; + set => m_Text.text = value; + } /// Constructor public HeaderFoldout() : base() { styleSheets.Add(AssetDatabase.LoadAssetAtPath(string.Format(k_StylesheetPathFormat, ""))); styleSheets.Add(AssetDatabase.LoadAssetAtPath(string.Format(k_StylesheetPathFormat, EditorGUIUtility.isProSkin ? "Dark" : "Light"))); - AddToClassList(k_Class); + AddToClassList(k_MainClass); RegisterCallback(DelayedInit); var line = hierarchy[0][0]; //pass by herarchy to ignore content redirection + m_IconElement = new Image() + { + style = + { + display = DisplayStyle.None // hidden by default, will be enabled if icon is set + } + }; + m_IconElement.AddToClassList(k_IconClass); + line.Add(m_IconElement); + + m_Toggle = new Toggle() + { + value = true + }; + m_Toggle.AddToClassList(k_EnableClass); + m_Toggle.RegisterValueChangedCallback(HandleDisabling); + m_Toggle.style.display = DisplayStyle.None; // hidden by default + line.Add(m_Toggle); + + m_Text = new Label(); + m_Text.AddToClassList(k_LabelClass); + line.Add(m_Text); + m_HelpButton = new Button(Background.FromTexture2D(CoreEditorStyles.iconHelp), () => Help.BrowseURL(m_DocumentationURL)); + m_HelpButton.AddToClassList(k_HelpButtonClass); m_HelpButton.SetEnabled(!string.IsNullOrEmpty(m_DocumentationURL)); line.Add(m_HelpButton); - m_ContextMenuButton = - new Button(Background.FromTexture2D(CoreEditorStyles.paneOptionsIcon), () => ShowMenu()) - { - style = - { - paddingRight = 2 - } - }; - + m_ContextMenuButton = new Button(Background.FromTexture2D(CoreEditorStyles.paneOptionsIcon), () => ShowMenu()); + m_ContextMenuButton.AddToClassList(k_ContextButtonClass); m_ContextMenuButton.SetEnabled(m_ContextMenuGenerator != null); line.Add(m_ContextMenuButton); - - m_IconElement = new Image(); - m_IconElement.name = k_IconName; - m_IconElement.style.display = DisplayStyle.None; // Disable by default, will be enabled if icon is set - // Delay insertion of icon to happen after foldout is constructed so we can put it in the right place - RegisterCallbackOnce(evt => line.Insert(1, m_IconElement)); } void DelayedInit(AttachToPanelEvent evt) { //Only show top line if previous item is not a HeaderFoldout to avoid bolder border - bool shouldShowTopLine = true; var parent = hierarchy.parent; int posInParent = parent.hierarchy.IndexOf(this); - if (posInParent > 0 && parent[posInParent - 1].ClassListContains(k_Class)) - shouldShowTopLine = false; + if (posInParent == 0 || !parent[posInParent - 1].ClassListContains(k_MainClass)) + AddToClassList("first-in-collection"); - style.borderTopWidth = shouldShowTopLine ? 1 : 0; + //fix to transfer label assigned in UXML from base label to new label + if (!string.IsNullOrEmpty(base.text)) + { + if (string.IsNullOrEmpty(m_Text.text)) + m_Text.text = base.text; + base.text = null; + } } void ShowMenu() @@ -113,40 +159,17 @@ namespace UnityEditor.Rendering var menu = m_ContextMenuGenerator.Invoke(); menu.DropDown(new Rect(m_ContextMenuButton.worldBound.position + m_ContextMenuButton.worldBound.size.y * Vector2.up, Vector2.zero)); } + + void HandleDisabling(ChangeEvent evt) + => contentContainer.SetEnabled(evt.newValue); } /// UITK component to display header styled foldout. This variant have an enable checkbox. + [Obsolete("Please directly use HeaderFoldout now #from(6000.2) (UnityUpgradable) -> HeaderFoldout", false)] public class HeaderToggleFoldout : HeaderFoldout { - private Toggle m_Toggle; - - /// Property to get the enablement state - public bool enabled - { - get => m_Toggle.value; - set => m_Toggle.value = value; - } - - /// Quick access to the enable toggle if one need to register events - public Toggle enableToggle => m_Toggle; - /// Constructor public HeaderToggleFoldout() : base() - { - var line = hierarchy[0][0]; //pass by herarchy to ignore content redirection - m_Toggle = new Toggle() - { - value = true, - name = "enable-checkbox", - }; - - //Need to delay insertion as foldout will be constructed after and we need to squeeze rigth after - RegisterCallbackOnce(evt => line.Insert(1, m_Toggle)); - - m_Toggle.RegisterValueChangedCallback(HandleDisabling); - } - - void HandleDisabling(ChangeEvent evt) - => contentContainer.SetEnabled(evt.newValue); + => showEnableCheckbox = true; } } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7368f52d0c8570ebc6936a6d2d9a9e925ef6f7e4 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_m)z5N7lYQuzQBWH0gbb!C6a$SWo%JGXMKGf-%Xr;B4q#NoHoH}W2G;BlS5`1OJl z96XGl4HzsqY|7?2ld@{FuNB!|>2VZ@-G5e=v zhOzX{&n&OoUw`{H&)hL{{#}^^J!frhu&ZjZRK%7|)7{W7 literal 0 HcmV?d00001 diff --git a/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png.meta b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png.meta new file mode 100644 index 00000000..dec7a618 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/MemorylessTexture@2x.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: ec3a3173916c141d8962a4466c366be6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..61eda112e6fbe97e06c3265fa8d05fd7ea52944c GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_m)z5N7lYQuzQBWH0gbb!C6a$SWpi?O!6X4=B{_>Eaj?aro`@jl9hP0?zjp*%Dex zPKM2F9!M@$mAusdyCG`yDz)`AN*DBn)xN)cB_GaiF&!OU`l!a z^=oTRO>v0};42X3SsE$N%J@mJFs-^z=oWw2-(PGz2@K2<2N>848W?#t)C+gbTyQdQ s*Mj_CDa>yJKV)}GUi__|GBt`(Sy*QJ+br`aptBe}UHx3vIVCg!008w=SpWb4 literal 0 HcmV?d00001 diff --git a/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png.meta b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png.meta new file mode 100644 index 00000000..4a6c4b74 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Icons/RenderGraphViewer/d_MemorylessTexture@2x.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: e813aef83a70543b79d435ef65ec86ee +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/CoreLightEditorUtilities.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/CoreLightEditorUtilities.cs index 1feb37ca..e894846f 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/CoreLightEditorUtilities.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/CoreLightEditorUtilities.cs @@ -315,7 +315,7 @@ namespace UnityEditor.Rendering var style = new GUIStyle { normal = { background = Texture2D.whiteTexture } }; GUI.color = new Color(0.82f, 0.82f, 0.82f, 1); - labelPosition = handlePosition + Handles.inverseMatrix.MultiplyVector(Vector3.up) * HandleUtility.GetHandleSize(handlePosition) * offsetFromHandle; + labelPosition = handlePosition + HandleUtility.GetHandleSize(handlePosition) * offsetFromHandle * Handles.inverseMatrix.MultiplyVector(Vector3.up); Handles.Label(labelPosition, labelText, style); } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.Invalidation.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.Invalidation.cs index 842f2a85..ebffb04e 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.Invalidation.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.Invalidation.cs @@ -61,7 +61,7 @@ namespace UnityEngine.Rendering // TODO: This whole process will need optimization. static bool NeighbourhoodIsEmptySpace(Vector3 pos, float searchDistance, Bounds boundsToCheckAgainst) { - Vector3 halfExtents = Vector3.one * searchDistance * 0.5f; + Vector3 halfExtents = 0.5f * searchDistance * Vector3.one; Vector3 brickCenter = pos + halfExtents; Collider[] colliders = Physics.OverlapBox(brickCenter, halfExtents); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs index 67d6182f..46df8365 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs @@ -151,13 +151,6 @@ namespace UnityEngine.Rendering context.Dispose(); } - // Fixup lighting for probes part of bricks with different subdivision levels - // When baking reflection probes, we want to skip this step - if (m_BakingBatch != null) - { - FixSeams(s_BakeData.positionRemap, positions, irradiance, validity, renderingLayerMasks); - } - return true; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs index 45851c6f..de20efb7 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs @@ -443,6 +443,7 @@ namespace UnityEngine.Rendering public int reflectionProbeCount; public NativeArray positionRemap; + public NativeArray originalPositions; public NativeArray sortedPositions; // Workers @@ -453,6 +454,9 @@ namespace UnityEngine.Rendering public RenderingLayerBaker layerMaskJob; public int cellIndex; + public Thread fixSeamsThread; + public bool doneFixingSeams; + // Progress reporting public BakingStep step; public ulong stepCount; @@ -466,6 +470,7 @@ namespace UnityEngine.Rendering reflectionProbeCount = requests.Count; jobs = CreateBakingJobs(bakingSet, requests.Count != 0); + originalPositions = probePositions.ToArray(Allocator.Persistent); SortPositions(probePositions, requests); virtualOffsetJob = virtualOffsetOverride ?? new DefaultVirtualOffset(); @@ -625,6 +630,7 @@ namespace UnityEngine.Rendering job.Dispose(); positionRemap.Dispose(); + originalPositions.Dispose(); sortedPositions.Dispose(); skyOcclusionJob.encodedDirections.Dispose(); @@ -641,7 +647,12 @@ namespace UnityEngine.Rendering static bool m_IsInit = false; static BakingBatch m_BakingBatch; - static ProbeVolumeBakingSet m_BakingSet = null; + static ProbeVolumeBakingSetWeakReference m_BakingSetReference = new(); + static ProbeVolumeBakingSet m_BakingSet + { + get => m_BakingSetReference.Get(); + set => m_BakingSetReference.Set(value); + } static TouchupVolumeWithBoundsList s_AdjustmentVolumes; static Bounds globalBounds = new Bounds(); @@ -883,6 +894,7 @@ namespace UnityEngine.Rendering SkyOcclusion, RenderingLayerMask, Integration, + FixSeams, FinalizeCells, Last = FinalizeCells + 1 @@ -1063,6 +1075,39 @@ namespace UnityEngine.Rendering } } + if (s_BakeData.step == BakingStep.FixSeams) + { + // Start fixing seams in the background + if (s_BakeData.fixSeamsThread == null) + { + s_BakeData.doneFixingSeams = false; + s_BakeData.fixSeamsThread = new Thread(() => + { + FixSeams( + s_BakeData.positionRemap, + s_BakeData.originalPositions, + s_BakeData.lightingJob.irradiance, + s_BakeData.lightingJob.validity, + s_BakeData.lightingJob.occlusion, + s_BakeData.skyOcclusionJob.occlusion, + s_BakeData.layerMaskJob.renderingLayerMasks); + + s_BakeData.doneFixingSeams = true; + }); + s_BakeData.fixSeamsThread.Start(); + } + // Wait until fixing seams is done + else + { + if (s_BakeData.doneFixingSeams) + { + s_BakeData.fixSeamsThread.Join(); + s_BakeData.fixSeamsThread = null; + s_BakeData.step++; + } + } + } + if (s_BakeData.step == BakingStep.FinalizeCells) { FinalizeCell(s_BakeData.cellIndex++, s_BakeData.positionRemap, @@ -1144,6 +1189,13 @@ namespace UnityEngine.Rendering LightingBaker.cancel = false; } + if (s_BakeData.fixSeamsThread != null) + { + LightingBaker.cancel = true; + s_BakeData.fixSeamsThread.Join(); + LightingBaker.cancel = false; + } + CleanBakeData(); } @@ -1233,13 +1285,22 @@ namespace UnityEngine.Rendering } } - static void FixSeams(NativeArray positionRemap, NativeArray positions, NativeArray sh, NativeArray validity, NativeArray renderingLayerMasks) + internal static void FixSeams( + NativeArray positionRemap, + NativeArray positions, + NativeArray sh, + NativeArray validity, + NativeArray probeOcclusion, + NativeArray skyOcclusion, + NativeArray renderingLayerMasks) { // Seams are caused are caused by probes on the boundary between two subdivision levels // The idea is to find first them and do a kind of dilation to smooth the values on the boundary // the dilation process consits in doing a trilinear sample of the higher subdivision brick and override the lower subdiv with that // We have to mark the probes on the boundary as valid otherwise leak reduction at runtime will interfere with this method + bool doProbeOcclusion = probeOcclusion.IsCreated && probeOcclusion.Length > 0; + bool doSkyOcclusion = skyOcclusion.IsCreated && skyOcclusion.Length > 0; // Use an indirection structure to ensure mem usage stays reasonable VoxelToBrickCache cache = new VoxelToBrickCache(); @@ -1332,7 +1393,9 @@ namespace UnityEngine.Rendering if (bakedRenderingLayerMasks) probeRenderingLayerMask = renderingLayerMasks[i]; float weightSum = 0.0f; - SphericalHarmonicsL2 trilinear = default; + SphericalHarmonicsL2 shTrilinear = default; + Vector4 probeOcclusionTrilinear = Vector4.zero; + Vector4 skyOcclusionTrilinear = Vector4.zero; for (int o = 0; o < 8; o++) { Vector3Int offset = GetSampleOffset(o); @@ -1355,24 +1418,44 @@ namespace UnityEngine.Rendering } // Do the lerp in compressed format to match result on GPU - var sample = sh[positionRemap[index]]; - BakingCell.CompressSH(ref sample, 1.0f, false); + var shSample = sh[positionRemap[index]]; + BakingCell.CompressSH(ref shSample, 1.0f, false); float trilinearW = ((offset.x == 1) ? fract.x : 1.0f - fract.x) * ((offset.y == 1) ? fract.y : 1.0f - fract.y) * ((offset.z == 1) ? fract.z : 1.0f - fract.z); - trilinear += sample * trilinearW; + shTrilinear += shSample * trilinearW; + + if (doProbeOcclusion) + probeOcclusionTrilinear += probeOcclusion[positionRemap[index]] * trilinearW; + + if (doSkyOcclusion) + skyOcclusionTrilinear += skyOcclusion[positionRemap[index]] * trilinearW; + weightSum += trilinearW; } } if (weightSum != 0.0f) { - trilinear *= 1.0f / weightSum; - BakingCell.DecompressSH(ref trilinear); - sh[i] = trilinear; + shTrilinear *= 1.0f / weightSum; + BakingCell.DecompressSH(ref shTrilinear); + sh[i] = shTrilinear; + + if (doProbeOcclusion) + { + probeOcclusionTrilinear *= 1.0f / weightSum; + probeOcclusion[i] = probeOcclusionTrilinear; + } + + if (doSkyOcclusion) + { + skyOcclusionTrilinear *= 1.0f / weightSum; + skyOcclusion[i] = skyOcclusionTrilinear; + } + validity[i] = k_MinValidityForLeaking; } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs index cf041304..65552dc6 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs @@ -117,6 +117,15 @@ namespace UnityEditor.Rendering if (!bakingSet.cellSharedDataAsset.IsValid()) // Not baked continue; + // APV doesn't work with WebGL, so let's warn the user. + if (buildPlayerContext.BuildPlayerOptions.target == BuildTarget.WebGL) + { + Debug.LogError( + $"The scene '{scene}' contains baked Adaptive Probe Volumes, but the build target is WebGL. " + + "Adaptive Probe Volumes are not supported when targeting WebGL."); + continue; + } + var bakingSetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(bakingSet)); var basePath = Path.Combine(tempStreamingAssetsPath, bakingSetGUID); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeEditor.cs index dffbc3e3..93fe0f07 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeEditor.cs @@ -148,7 +148,7 @@ namespace UnityEditor.Rendering if (ProbeVolumeLightingTab.GetLightingSettings().realtimeGI) { - EditorGUILayout.HelpBox("Adaptive Probe Volumes are not supported when using Enlighten.", MessageType.Warning, wide: true); + EditorGUILayout.HelpBox("Adaptive Probe Volumes are not supported when using Realtime Global Illumination(Enlighten).", MessageType.Warning, wide: true); drawInspector = false; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs index e0275f52..4e087fe4 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs @@ -112,18 +112,18 @@ namespace UnityEngine.Rendering bool m_TempBakingSet = false; bool m_Initialized = false; - ProbeVolumeBakingSet m_ActiveSet; + ProbeVolumeBakingSetWeakReference m_ActiveSet = new(); ProbeVolumeBakingSet activeSet { - get => m_ActiveSet; + get => m_ActiveSet.Get(); set { - if (ReferenceEquals(m_ActiveSet, value)) return; - if (m_TempBakingSet) Object.DestroyImmediate(m_ActiveSet); - m_ActiveSet = value; + if (ReferenceEquals(m_ActiveSet.Get(), value)) return; + if (m_TempBakingSet) Object.DestroyImmediate(m_ActiveSet.Get()); + m_ActiveSet.Set(value); m_TempBakingSet = false; - if (m_ActiveSet == null) return; - m_SingleSceneMode = m_ActiveSet.singleSceneMode; + if (m_ActiveSet.Get() == null) return; + m_SingleSceneMode = m_ActiveSet.Get().singleSceneMode; InitializeSceneList(); } } @@ -169,14 +169,14 @@ namespace UnityEngine.Rendering bool FindActiveSet() { - if (m_ActiveSet == null) + if (m_ActiveSet.Get() == null) { activeSet = ProbeVolumeBakingSet.GetBakingSetForScene(SceneManager.GetActiveScene()); for (int i = 0; activeSet == null && i < SceneManager.sceneCount; i++) activeSet = ProbeVolumeBakingSet.GetBakingSetForScene(SceneManager.GetSceneAt(i)); } - return m_ActiveSet != null; + return m_ActiveSet.Get() != null; } void Initialize() @@ -359,6 +359,8 @@ namespace UnityEngine.Rendering { if (newSet != null) { EditorUtility.SetDirty(newSet); newSet.singleSceneMode = false; } activeSet = newSet; + + ProbeReferenceVolume.instance.Clear(); } if (activeSet != null) @@ -493,7 +495,7 @@ namespace UnityEngine.Rendering set = ScriptableObject.CreateInstance(); set.SetDefaults(); - ProbeReferenceVolume.instance.AddPendingSceneRemoval(sceneGUID); + ProbeReferenceVolume.instance.Clear(); } EditorUtility.SetDirty(set); diff --git a/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraController.cs b/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraController.cs index a2271c88..c38ea5e3 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraController.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraController.cs @@ -313,7 +313,7 @@ namespace UnityEditor.Rendering.LookDev m_FlySpeedAccelerated = 9; else m_FlySpeedAccelerated *= Mathf.Pow(k_FlyAcceleration, deltaTime); - result = m_MotionDirection.normalized * m_FlySpeedAccelerated * speed * deltaTime; + result = m_FlySpeedAccelerated * speed * deltaTime * m_MotionDirection.normalized; return result; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraState.cs b/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraState.cs index e813437b..c721b52f 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/LookDev/CameraState.cs @@ -78,8 +78,8 @@ namespace UnityEditor.Rendering.LookDev screenPoint.x * 2f / screen.width - 1f, screenPoint.y * 2f / screen.height - 1f); return pivot - - up * verticalDistance * normalizedScreenPoint.y - - right * verticalDistance * aspect * normalizedScreenPoint.x; + - verticalDistance * normalizedScreenPoint.y * up + - verticalDistance * aspect * normalizedScreenPoint.x * right; } //Pivot is always on center axis by construction @@ -92,8 +92,7 @@ namespace UnityEditor.Rendering.LookDev /// The camera to update public void UpdateCamera(Camera camera) { - camera.transform.rotation = rotation; - camera.transform.position = position; + camera.transform.SetPositionAndRotation(position, rotation); camera.nearClipPlane = nearClip; camera.farClipPlane = farClip; camera.fieldOfView = fieldOfView; diff --git a/Packages/com.unity.render-pipelines.core/Editor/LookDev/ComparisonGizmoController.cs b/Packages/com.unity.render-pipelines.core/Editor/LookDev/ComparisonGizmoController.cs index 9d8a9b56..3e59e606 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/LookDev/ComparisonGizmoController.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/LookDev/ComparisonGizmoController.cs @@ -211,7 +211,7 @@ namespace UnityEditor.Rendering.LookDev if (absDistanceToPlane < ComparisonGizmoState.thicknessSelected) selected = Selected.PlaneSeparator; - Vector2 circleCenter = m_State.center + side * orthoPlaneNormal * m_State.length; + Vector2 circleCenter = m_State.center + m_State.length * side * orthoPlaneNormal; float d = Vector2.Distance(normalizedMousePosition, circleCenter); if (d <= ComparisonGizmoState.circleRadiusSelected) selected = side > 0.0f ? Selected.NodeFirstView : Selected.NodeSecondView; diff --git a/Packages/com.unity.render-pipelines.core/Editor/LookDev/Stage.cs b/Packages/com.unity.render-pipelines.core/Editor/LookDev/Stage.cs index b900ec54..35cf5845 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/LookDev/Stage.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/LookDev/Stage.cs @@ -104,8 +104,7 @@ namespace UnityEditor.Rendering.LookDev return; SceneManager.MoveGameObjectToScene(gameObject, m_PreviewScene); - gameObject.transform.position = position; - gameObject.transform.rotation = rotation; + gameObject.transform.SetPositionAndRotation(position, rotation); if (persistent) m_PersistentGameObjects.Add(gameObject); else @@ -195,16 +194,13 @@ namespace UnityEditor.Rendering.LookDev go.hideFlags = HideFlags.HideAndDontSave; go.layer = k_PreviewCullingLayerIndex; - var meshRenderer = go.GetComponent(); - if (meshRenderer != null) + if (go.TryGetComponent(out var meshRenderer)) meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; - var skinnedMeshRenderer = go.GetComponent(); - if (skinnedMeshRenderer != null) + if (go.TryGetComponent(out var skinnedMeshRenderer)) skinnedMeshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; - var lineRenderer = go.GetComponent(); - if (lineRenderer != null) + if (go.TryGetComponent(out var lineRenderer)) lineRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; var volumes = go.GetComponents(); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Properties/AdvancedProperties.cs b/Packages/com.unity.render-pipelines.core/Editor/Properties/AdvancedProperties.cs index c35644cf..21d8361a 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Properties/AdvancedProperties.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Properties/AdvancedProperties.cs @@ -120,7 +120,10 @@ namespace UnityEditor.Rendering animation ??= s_AnimFloat; - GUI.color = Color.Lerp(CoreEditorStyles.backgroundColor * oldColor, CoreEditorStyles.backgroundHighlightColor, animation.value); + Color transparent = CoreEditorStyles.backgroundHighlightColor; + transparent.a = 0f; + + GUI.color = Color.Lerp(transparent, CoreEditorStyles.backgroundHighlightColor, animation.value); EditorGUILayout.BeginVertical(CoreEditorStyles.additionalPropertiesHighlightStyle); GUI.color = oldColor; diff --git a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.SidePanel.cs b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.SidePanel.cs index bd77c36e..c670fbd4 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.SidePanel.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.SidePanel.cs @@ -66,7 +66,11 @@ namespace UnityEditor.Rendering rootVisualElement.RegisterCallback(_ => { SaveSplitViewFixedPaneHeight(); // Window resized - save the current pane height - UpdatePanelHeights(); + + // TwoPaneSplitView also updates draglineanchor offset using the same event, conflicting with what we + // do here. Deferring our panel height update to next frame solves a bug with dragline "jumping" when + // window is resized down vertically and the lower panel is already at minimum height. + rootVisualElement.schedule.Execute(UpdatePanelHeights); }); var contentSplitView = rootVisualElement.Q(Names.kContentContainer); @@ -271,7 +275,7 @@ namespace UnityEditor.Rendering var foldoutCheckmark = resourceItem.Q("unity-checkmark"); // Add resource type icon before the label - foldoutCheckmark.parent.Insert(1, CreateResourceTypeIcon(visibleResourceElement.type)); + foldoutCheckmark.parent.Insert(1, CreateResourceTypeIcon(visibleResourceElement.type, resourceData.memoryless)); foldoutCheckmark.parent.Add(iconContainer); foldoutCheckmark.BringToFront(); // Move foldout checkmark to the right diff --git a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.cs b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.cs index d6a78d50..bdd225a4 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.cs @@ -24,6 +24,7 @@ namespace UnityEditor.Rendering public const string kCurrentExecutionDropdown = "current-execution-dropdown"; public const string kPassFilterField = "pass-filter-field"; public const string kResourceFilterField = "resource-filter-field"; + public const string kViewOptionsField = "view-options-field"; public const string kContentContainer = "content-container"; public const string kMainContainer = "main-container"; public const string kPassList = "pass-list"; @@ -34,6 +35,7 @@ namespace UnityEditor.Rendering public const string kGridlineContainer = "grid-line-container"; public const string kHoverOverlay = "hover-overlay"; public const string kEmptyStateMessage = "empty-state-message"; + public const string kPassListCornerOccluder = "pass-list-corner-occluder"; } static partial class Classes @@ -63,6 +65,7 @@ namespace UnityEditor.Rendering public const string kResourceIconGlobalLight = "resource-icon--global-light"; public const string kResourceIconFbfetch = "resource-icon--fbfetch"; public const string kResourceIconTexture = "resource-icon--texture"; + public const string kResourceIconMemorylessTexture = "resource-icon--memoryless-texture"; public const string kResourceIconBuffer = "resource-icon--buffer"; public const string kResourceIconAccelerationStructure = "resource-icon--acceleration-structure"; public const string kResourceGridRow = "resource-grid__row"; @@ -77,6 +80,17 @@ namespace UnityEditor.Rendering public const string kResourceDependencyBlockReadWrite = "dependency-block-readwrite"; public const string kGridLine = "grid-line"; public const string kGridLineHighlight = "grid-line--highlight"; + public const string kLoadAction = "dependency-block-load-action"; + public const string kLoadActionLoad = "load-action-load"; + public const string kLoadActionClear = "load-action-clear"; + public const string kLoadActionDontCare = "load-action-dont-care"; + public const string kStoreAction = "dependency-block-store-action"; + public const string kStoreActionStore = "store-action-store"; + public const string kStoreActionResolve = "store-action-resolve"; + public const string kStoreActionStoreAndResolve = "store-action-store-resolve"; + public const string kStoreActionDontCare = "store-action-dont-care"; + public const string kLoadActionBorder = "dependency-block-load-action-border"; + public const string kStoreActionBorder = "dependency-block-store-action-border"; } const string k_TemplatePath = "Packages/com.unity.render-pipelines.core/Editor/UXML/RenderGraphViewer.uxml"; @@ -121,6 +135,7 @@ namespace UnityEditor.Rendering const string kPassFilterEditorPrefsKey = "RenderGraphViewer.PassFilter"; const string kResourceFilterEditorPrefsKey = "RenderGraphViewer.ResourceFilter"; const string kSelectedExecutionEditorPrefsKey = "RenderGraphViewer.SelectedExecution"; + const string kViewOptionsEditorPrefsKey = "RenderGraphViewer.ViewOptions"; PassFilter m_PassFilter = PassFilter.CulledPasses | PassFilter.RasterPasses | PassFilter.UnsafePasses | PassFilter.ComputePasses; PassFilterLegacy m_PassFilterLegacy = PassFilterLegacy.CulledPasses; @@ -129,6 +144,8 @@ namespace UnityEditor.Rendering ResourceFilter.ImportedResources | ResourceFilter.Textures | ResourceFilter.Buffers | ResourceFilter.AccelerationStructures; + ViewOptions m_ViewOptions = 0; + enum EmptyStateReason { None = 0, @@ -151,6 +168,23 @@ namespace UnityEditor.Rendering L10n.Tr("No resources to display. Select a different Resource Filter to display contents.") }; + private static readonly string[] kLoadActionNames = + { + "", + L10n.Tr("Load"), + L10n.Tr("Clear"), + L10n.Tr("Don't Care"), + }; + + private static readonly string[] kStoreActionNames = + { + "", + L10n.Tr("Store"), + L10n.Tr("Resolve"), + L10n.Tr("Store and Resolve"), + L10n.Tr("Don't Care"), + }; + static readonly string kOpenInCSharpEditorTooltip = L10n.Tr("Click to open {0} definition in C# editor."); [MenuItem("Window/Analysis/Render Graph Viewer", false, 10006)] @@ -158,6 +192,7 @@ namespace UnityEditor.Rendering { var window = GetWindow(); window.titleContent = new GUIContent("Render Graph Viewer"); + window.minSize = new Vector2(880f, 300f); } [Flags] @@ -184,6 +219,12 @@ namespace UnityEditor.Rendering AccelerationStructures = 1 << 3, } + [Flags] + enum ViewOptions + { + LoadStoreActions = 1 << 0, + } + class ResourceElementInfo { public RenderGraphResourceType type; @@ -205,11 +246,31 @@ namespace UnityEditor.Rendering FramebufferFetch = 1 << 1, } + public enum LoadAction + { + None, + Load, + Clear, + DontCare, + } + + public enum StoreAction + { + None, + Store, + Resolve, + StoreAndResolve, + DontCare, + } + public VisualElement element; public string tooltip; public int visibleResourceIndex; public bool read; public bool write; + public bool memoryless; + public LoadAction load; + public StoreAction store; public UsageFlags usage; public bool HasMultipleUsageFlags() @@ -925,6 +986,13 @@ namespace UnityEditor.Rendering RebuildGraphViewerUI(); } + void OnViewOptionsChanged(ChangeEvent evt) + { + m_ViewOptions = (ViewOptions) evt.newValue; + EditorPrefs.SetInt(kViewOptionsEditorPrefsKey, (int)m_ViewOptions); + RebuildGraphViewerUI(); + } + void RebuildPassFilterUI() { var passFilter = rootVisualElement.Q(Names.kPassFilterField); @@ -953,6 +1021,15 @@ namespace UnityEditor.Rendering resourceFilter.RegisterCallback>(OnResourceFilterChanged); } + void RebuildViewOptionsUI() + { + var viewOptions = rootVisualElement.Q(Names.kViewOptionsField); + viewOptions.style.display = DisplayStyle.Flex; + viewOptions.UnregisterCallback>(OnViewOptionsChanged); + viewOptions.Init(m_ViewOptions); + viewOptions.RegisterCallback>(OnViewOptionsChanged); + } + void RebuildHeaderUI() { RebuildRenderGraphPopup(); @@ -1048,6 +1125,9 @@ namespace UnityEditor.Rendering static readonly string[] k_ResourceNames = { "Texture Resource", "Buffer Resource", "Acceleration Structure Resource" }; + static readonly string[] k_MemorylessResourceNames = + { "Memoryless Texture Resource", "Memoryless Buffer Resource", "Memoryless Acceleration Structure Resource" }; + // Pass title ellipsis must be generated manually because it can't be done right for rotated text using uss. void TruncatePassTitle(GeometryChangedEvent evt) @@ -1216,19 +1296,19 @@ namespace UnityEditor.Rendering return gridline; } - VisualElement CreateResourceTypeIcon(RenderGraphResourceType type) + VisualElement CreateResourceTypeIcon(RenderGraphResourceType type, bool memoryless) { var resourceTypeIcon = new VisualElement(); resourceTypeIcon.AddToClassList(Classes.kResourceIcon); string className = type switch { - RenderGraphResourceType.Texture => Classes.kResourceIconTexture, + RenderGraphResourceType.Texture => memoryless ? Classes.kResourceIconMemorylessTexture : Classes.kResourceIconTexture, RenderGraphResourceType.Buffer => Classes.kResourceIconBuffer, RenderGraphResourceType.AccelerationStructure => Classes.kResourceIconAccelerationStructure, _ => throw new ArgumentOutOfRangeException(nameof(type)) }; resourceTypeIcon.AddToClassList(className); - resourceTypeIcon.tooltip = k_ResourceNames[(int)type]; + resourceTypeIcon.tooltip = memoryless ? k_MemorylessResourceNames[(int)type] : k_ResourceNames[(int)type]; return resourceTypeIcon; } @@ -1238,7 +1318,7 @@ namespace UnityEditor.Rendering resourceListItem.AddToClassList(Classes.kResourceListItem); var resourceTitleContainer = new VisualElement(); - resourceTitleContainer.Add(CreateResourceTypeIcon(type)); + resourceTitleContainer.Add(CreateResourceTypeIcon(type, res.memoryless)); var resourceLabel = new Label(); resourceLabel.text = res.name; @@ -1308,6 +1388,22 @@ namespace UnityEditor.Rendering if (!string.IsNullOrEmpty(accessType)) tooltip += $"{accessType} access to this resource."; + if (block.load != ResourceRWBlock.LoadAction.None) + { + if (tooltip.Length > 0) + tooltip += "
"; + + tooltip += $"Load Action: {kLoadActionNames[(int)block.load]}"; + } + + if (block.store != ResourceRWBlock.StoreAction.None) + { + if (tooltip.Length > 0) + tooltip += "
"; + + tooltip += $"Store Action: {kStoreActionNames[(int)block.store]}"; + } + if (block.usage != ResourceRWBlock.UsageFlags.None) { string resourceIconClassName = string.Empty; @@ -1334,6 +1430,66 @@ namespace UnityEditor.Rendering tooltip += "
- Read is using framebuffer fetch."; if (block.usage.HasFlag(ResourceRWBlock.UsageFlags.UpdatesGlobalResource)) tooltip += "
- Updates a global resource slot."; + if (block.memoryless) + tooltip += "
- Memory usage is memoryless."; + } + + if (m_ViewOptions.HasFlag(ViewOptions.LoadStoreActions)) + { + if (block.load != ResourceRWBlock.LoadAction.None) + { + var loadActionBorder = new TriangleElement { useStyle = true }; + loadActionBorder.AddToClassList(Classes.kLoadAction); + loadActionBorder.AddToClassList(Classes.kLoadActionBorder); + + var loadAction = new TriangleElement { useStyle = true }; + loadAction.AddToClassList(Classes.kLoadAction); + + switch (block.load) + { + case ResourceRWBlock.LoadAction.Load: + loadAction.AddToClassList(Classes.kLoadActionLoad); + break; + case ResourceRWBlock.LoadAction.Clear: + loadAction.AddToClassList(Classes.kLoadActionClear); + break; + case ResourceRWBlock.LoadAction.DontCare: + loadAction.AddToClassList(Classes.kLoadActionDontCare); + break; + } + + block.element.Add(loadActionBorder); + block.element.Add(loadAction); + } + + if( block.store != ResourceRWBlock.StoreAction.None) + { + var storeActionBorder = new TriangleElement { useStyle = true }; + storeActionBorder.AddToClassList(Classes.kStoreAction); + storeActionBorder.AddToClassList(Classes.kStoreActionBorder); + + var storeAction = new TriangleElement { useStyle = true }; + storeAction.AddToClassList(Classes.kStoreAction); + + switch (block.store) + { + case ResourceRWBlock.StoreAction.Store: + storeAction.AddToClassList(Classes.kStoreActionStore); + break; + case ResourceRWBlock.StoreAction.Resolve: + storeAction.AddToClassList(Classes.kStoreActionResolve); + break; + case ResourceRWBlock.StoreAction.StoreAndResolve: + storeAction.AddToClassList(Classes.kStoreActionStoreAndResolve); + break; + case ResourceRWBlock.StoreAction.DontCare: + storeAction.AddToClassList(Classes.kStoreActionDontCare); + break; + } + + block.element.Add(storeActionBorder); + block.element.Add(storeAction); + } } block.tooltip = tooltip; @@ -1397,20 +1553,97 @@ namespace UnityEditor.Rendering foreach (var writePassId in res.producerList) blocks[writePassId].write = true; + var currentResource = m_CurrentDebugData.resourceLists[(int)resourceType][resourceIndex]; + HashSet uniqueRenderPassInfos = new(); + + // Build pass blocks for (int passId = 0; passId < blocks.Count; passId++) { ResourceRWBlock block = blocks[passId]; - if (m_PassIdToVisiblePassIndex.TryGetValue(passId, out int visiblePassIndex)) + var pass = m_CurrentDebugData.passList[passId]; + if (resourceType == RenderGraphResourceType.Texture && pass.nrpInfo != null) + { + if (pass.nrpInfo.textureFBFetchList.Contains(resourceIndex)) + block.usage |= ResourceRWBlock.UsageFlags.FramebufferFetch; + if (pass.nrpInfo.setGlobals.Contains(resourceIndex)) + block.usage |= ResourceRWBlock.UsageFlags.UpdatesGlobalResource; + if (pass.nrpInfo.nativePassInfo != null) + { + uniqueRenderPassInfos.Add(pass.nrpInfo.nativePassInfo); + + foreach (var attachmentInfo in pass.nrpInfo.nativePassInfo.attachmentInfos) + { + if (attachmentInfo.resourceName == currentResource.name) + { + block.memoryless = attachmentInfo.attachment.memoryless; + + block.load = attachmentInfo.attachment.loadAction switch + { + RenderBufferLoadAction.Load => ResourceRWBlock.LoadAction.Load, + RenderBufferLoadAction.Clear => ResourceRWBlock.LoadAction.Clear, + RenderBufferLoadAction.DontCare => ResourceRWBlock.LoadAction.DontCare, + _ => ResourceRWBlock.LoadAction.None + }; + + block.store = attachmentInfo.attachment.storeAction switch + { + RenderBufferStoreAction.Store => ResourceRWBlock.StoreAction.Store, + RenderBufferStoreAction.Resolve => ResourceRWBlock.StoreAction.Resolve, + RenderBufferStoreAction.StoreAndResolve => ResourceRWBlock.StoreAction.StoreAndResolve, + RenderBufferStoreAction.DontCare => ResourceRWBlock.StoreAction.DontCare, + _ => ResourceRWBlock.StoreAction.None, + }; + break; + } + } + } + } + } + + // Adjust blocks to only show first load/store actions for each merged native render pass + foreach (var nrpInfo in uniqueRenderPassInfos) + { + int minLoadPass = int.MaxValue; + int maxStorePass = int.MinValue; + + // Find the first and last load/store pair + foreach (int mergedPassId in nrpInfo.mergedPassIds) { - var pass = m_CurrentDebugData.passList[passId]; - if (resourceType == RenderGraphResourceType.Texture && pass.nrpInfo != null) + var mergedPass = m_CurrentDebugData.passList[mergedPassId]; + foreach (var attachmentInfo in mergedPass.nrpInfo.nativePassInfo.attachmentInfos) { - if (pass.nrpInfo.textureFBFetchList.Contains(resourceIndex)) - block.usage |= ResourceRWBlock.UsageFlags.FramebufferFetch; - if (pass.nrpInfo.setGlobals.Contains(resourceIndex)) - block.usage |= ResourceRWBlock.UsageFlags.UpdatesGlobalResource; + bool read = mergedPass.resourceReadLists[(int)resourceType].Contains(resourceIndex); + bool write = mergedPass.resourceWriteLists[(int)resourceType].Contains(resourceIndex); + if (attachmentInfo.resourceName == currentResource.name && (read || write)) + { + minLoadPass = Mathf.Min(minLoadPass, mergedPassId); + maxStorePass = Mathf.Max(maxStorePass, mergedPassId); + } } + } + // Remove load/store actions between the first load and last store pass + if (minLoadPass < maxStorePass) + { + blocks[minLoadPass].store = ResourceRWBlock.StoreAction.None; + + for (int i = minLoadPass + 1, imax = maxStorePass; i < imax; ++i) + { + var block = blocks[i]; + block.load = ResourceRWBlock.LoadAction.None; + block.store = ResourceRWBlock.StoreAction.None; + } + + blocks[maxStorePass].load = ResourceRWBlock.LoadAction.None; + } + } + + // Add blocks that are visible + for (int passId = 0; passId < blocks.Count; passId++) + { + ResourceRWBlock block = blocks[passId]; + if (m_PassIdToVisiblePassIndex.TryGetValue(passId, out int visiblePassIndex)) + { if (!block.read && !block.write && block.usage == ResourceRWBlock.UsageFlags.None) continue; // No need to create a visual element @@ -1586,6 +1819,27 @@ namespace UnityEditor.Rendering RebuildGraphViewerUI(); } + void RerouteWheelEvent(VisualElement source, VisualElement target) + { + source.RegisterCallback(evt => + { + evt.StopImmediatePropagation(); + + // Need to create an intermediate Event to be able to call WheelEvent.GetPooled() + var imguiEvt = new Event { + type = EventType.ScrollWheel, + delta = new Vector2(evt.delta.x, evt.delta.y), + mousePosition = evt.mousePosition, + modifiers = evt.modifiers + }; + using (var newEvt = WheelEvent.GetPooled(imguiEvt)) + { + newEvt.target = target; + target.SendEvent(newEvt); + } + }, TrickleDown.TrickleDown); + } + // Initialize, register callbacks & manipulators etc. once void InitializePersistentElements() { @@ -1617,6 +1871,9 @@ namespace UnityEditor.Rendering var resourceFilter = rootVisualElement.Q(Names.kResourceFilterField); resourceFilter.style.display = DisplayStyle.None; // Hidden until the compiler is known + var viewOptions = rootVisualElement.Q(Names.kViewOptionsField); + viewOptions.style.display = DisplayStyle.None; + // Hover overlay var hoverOverlay = rootVisualElement.Q(Names.kHoverOverlay); hoverOverlay.RegisterCallback(_ => HoverResourceGrid(-1, -1)); @@ -1647,9 +1904,12 @@ namespace UnityEditor.Rendering resourceGridScrollView.horizontalScroller.valueChanged += value => passListScrollView.scrollOffset = new Vector2(value, passListScrollView.scrollOffset.y); - // Disable mouse wheel on the scroll views that are synced to the resource grid - resourceListScrollView.RegisterCallback(evt => evt.StopImmediatePropagation(), TrickleDown.TrickleDown); - passListScrollView.RegisterCallback(evt => evt.StopImmediatePropagation(), TrickleDown.TrickleDown); + // Scroll views are synced to the resource grid, so we don't want them to scroll independently. To have + // consistent behavior, redirect the wheel events to the resource grid and let it handle them. + RerouteWheelEvent(resourceListScrollView, resourceGridScrollView); + RerouteWheelEvent(passListScrollView, resourceGridScrollView); + var passListCornerOccluder = rootVisualElement.Q(Names.kPassListCornerOccluder); + RerouteWheelEvent(passListCornerOccluder, resourceGridScrollView); InitializeSidePanel(); } @@ -1706,32 +1966,32 @@ namespace UnityEditor.Rendering RebuildPassFilterUI(); RebuildResourceFilterUI(); + RebuildViewOptionsUI(); RebuildGraphViewerUI(); } } }; } - void OnEnable() + void CreateGUI() { - var registeredGraph = RenderGraph.GetRegisteredRenderGraphs(); - foreach (var graph in registeredGraph) - m_RegisteredGraphs.Add(graph, new HashSet()); - - SubscribeToRenderGraphEvents(); - if (EditorPrefs.HasKey(kPassFilterLegacyEditorPrefsKey)) m_PassFilterLegacy = (PassFilterLegacy)EditorPrefs.GetInt(kPassFilterLegacyEditorPrefsKey); if (EditorPrefs.HasKey(kPassFilterEditorPrefsKey)) m_PassFilter = (PassFilter)EditorPrefs.GetInt(kPassFilterEditorPrefsKey); if (EditorPrefs.HasKey(kResourceFilterEditorPrefsKey)) m_ResourceFilter = (ResourceFilter)EditorPrefs.GetInt(kResourceFilterEditorPrefsKey); + if (EditorPrefs.HasKey(kViewOptionsEditorPrefsKey)) + m_ViewOptions = (ViewOptions)EditorPrefs.GetInt(kViewOptionsEditorPrefsKey); GraphicsToolLifetimeAnalytic.WindowOpened(); - } - void CreateGUI() - { + var registeredGraph = RenderGraph.GetRegisteredRenderGraphs(); + foreach (var graph in registeredGraph) + m_RegisteredGraphs.Add(graph, new HashSet()); + + SubscribeToRenderGraphEvents(); + m_ResourceListIcon = AssetDatabase.LoadAssetAtPath(string.Format(k_ResourceListIconPath, EditorGUIUtility.isProSkin ? "d_" : "")); m_PassListIcon = AssetDatabase.LoadAssetAtPath(string.Format(k_PassListIconPath, EditorGUIUtility.isProSkin ? "d_" : "")); @@ -1791,11 +2051,18 @@ namespace UnityEditor.Rendering public Color color { get; set; } + public bool useStyle { get; set; } + public TriangleElement() { generateVisualContent += ctx => { var painter = ctx.painter2D; + var resolvedStyle = ctx.visualElement.resolvedStyle; + var color = useStyle ? resolvedStyle.color : this.color; + var width = useStyle ? resolvedStyle.width : this.width; + var height = useStyle ? resolvedStyle.height : this.height; + painter.fillColor = color; painter.BeginPath(); painter.MoveTo(new Vector2(0, height)); diff --git a/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs b/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs index 56d25b9a..64f37596 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs @@ -48,7 +48,14 @@ class SampleDependencyImporter : IPackageManagerExtension PackageManagerExtensions.RegisterExtension(new SampleDependencyImporter()); } - const string k_unityPrefixPackage = "com.unity."; + string[] allowedPackageList = + { + "com.unity.render-pipelines.high-definition", + "com.unity.render-pipelines.universal", + "com.unity.shadergraph", + "com.unity.visualeffectgraph" + }; + bool importingTextMeshProEssentialResources = false; PackageInfo m_PackageInfo; @@ -65,16 +72,27 @@ class SampleDependencyImporter : IPackageManagerExtension ///
void IPackageManagerExtension.OnPackageSelectionChange(PackageInfo packageInfo) { - var isUnityPackage = packageInfo != null && packageInfo.name.StartsWith(k_unityPrefixPackage); - - if (isUnityPackage) - { + if (packageInfo == null) + return; + + // Triggers the dependencies import only on specific packages + bool packageFound = false; + foreach (string name in allowedPackageList) + if (name == packageInfo.name) + { + packageFound = true; + break; + } - - - m_PackageInfo = packageInfo; - m_Samples = GetSamples(packageInfo); + if (!packageFound) + return; + + m_PackageInfo = packageInfo; + m_Samples = GetSamples(packageInfo); + // Only trigger the import if the package has samples. + if (m_Samples != null && m_Samples.Count > 0) + { if (TryLoadSampleConfiguration(m_PackageInfo, out m_SampleList)) { SamplePostprocessor.AssetImported += LoadAssetDependencies; diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView.meta b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates.meta similarity index 77% rename from Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView.meta rename to Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates.meta index 1ce1b2c2..d0b42259 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/TabbedView.meta +++ b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2e38f5e180a291347b3243609946381c +guid: 863f1a3fb862346d7a3344bcb3024f1b folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt new file mode 100644 index 00000000..76881f75 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt @@ -0,0 +1,31 @@ +Shader "Custom/#SCRIPTNAME#" +{ + SubShader + { + HLSLINCLUDE + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" + ENDHLSL + + Tags { "RenderType"="Opaque" } + LOD 100 + ZWrite Off Cull Off + Pass + { + Name "#SCRIPTNAME#" + + HLSLPROGRAM + + #pragma vertex Vert + #pragma fragment Frag + + float4 Frag (Varyings input) : SV_Target + { + float4 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, input.texcoord).rgba; + return color; + } + + ENDHLSL + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt.meta b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt.meta new file mode 100644 index 00000000..bae723e8 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/BlitSRP.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0c69256ff57964383b6408cfd6119fb3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs new file mode 100644 index 00000000..58b3cbdd --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs @@ -0,0 +1,13 @@ +namespace UnityEditor.Rendering +{ + internal static class ScriptTemplates + { + internal const string ScriptTemplatePath = "Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/"; + + [MenuItem("Assets/Create/Shader/SRP Blit Shader", priority = 1)] + static void CreateBlitSRPShader() + { + ProjectWindowUtil.CreateScriptAssetFromTemplateFile($"{ScriptTemplatePath}BlitSRP.txt", "NewBlitScriptableRenderPipelineShader.shader"); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs.meta new file mode 100644 index 00000000..95bfb8aa --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/ScriptTemplates/ScriptTemplates.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c870ee1bdda2f46839aa9823ce9d94ca \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldout.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldout.uss index 2c4a8600..98d3b2f8 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldout.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldout.uss @@ -1,70 +1,107 @@ .header-foldout { - border-width: 1px 0px 1px 0px; + border-width: 0px 0px 1px 0px; border-color: var(--unity-colors-inspector_titlebar-border); +} + +.header-foldout.first-in-collection +{ + border-top-width: 1px; +} - /* ensure border take all width */ - margin: 0px -6px 0px -31px; - padding: 0px 0px 0px 0; +.unity-inspector-element__custom-inspector-container > .header-foldout +{ + /* At root of inspector we need to remove the Padding of the InspectorElement */ + margin: 0px -6px 0px -15px; } -.header-foldout > Toggle +.unity-foldout__toggle { - /* ensure background take all width */ margin: 0px 0px 0px 0px; - padding: 0px 6px 0px 31px; } -.header-foldout > Toggle Label + +.unity-foldout__toggle Image { - -unity-font-style: bold; - font-size: 13px; - flex-grow: 1; + min-width: 16px; } -.header-foldout > Toggle Button +.unity-foldout__input { - background-color: transparent; - border-width: 0px; - margin: 1px 2px 1px 0px; - padding: 0px 0px 0px 0px; - border-radius: 0px; + flex-shrink: 1; } -.header-foldout > Toggle Button:hover +.unity-foldout__toggle #unity-checkmark { - background-color: var(--unity-colors-button-background-hover); + margin: 0px 2px 0px 4px; } -.header-foldout > Toggle Button:disabled +.header-foldout__icon { - display: none; + margin: 1px 2px 0px 1px; + height: 16px; + width: 16px; } -.header-foldout > Toggle Image +.header-foldout__enable { - min-width: 16px; + margin: 2px 1px 2px 0px; + height: 16px; + width: 16px; } -.header-foldout > #unity-content +.header-foldout__enable #unity-checkmark { - margin: 0px 5px 0px 47px; + margin: 0px 2px 0px 2px; + background-size: 80% 80%; } -.header-foldout #enable-checkbox +.header-foldout__label { - margin: 2px 6px 3px 1px; + -unity-font-style: bold; + font-size: 13px; + flex-grow: 1; + flex-shrink: 1; + margin: 0px 0px 0px 3px; + overflow: hidden; } -.header-foldout #enable-checkbox #unity-checkmark +.header-foldout__help-button { - background-size: 80% 80%; + background-color: transparent; + margin: 2px 4px 1px 3px; + padding: 0px 2px 0px 0px; + border-width: 0px; + border-radius: 2px 2px 2px 2px; + width: 16px; + height: 16px; } -.header-foldout #header-foldout__icon +.header-foldout__context-button { - margin-top: 2px; - margin-right: 6px; - height: 16px; + background-color: transparent; + margin: 2px 5px 1px 0px; + padding: 0px 2px 0px 0px; + border-width: 0px; + border-radius: 2px 2px 2px 2px; width: 16px; + height: 16px; +} + +.header-foldout__help-button:hover, +.header-foldout__context-button:hover +{ + background-color: var(--unity-colors-button-background-hover); +} + +.header-foldout__help-button:disabled, +.header-foldout__context-button:disabled +{ + display: none; +} + +.project-settings-section__content .header-foldout__context-button +{ + /* Specific fix for alignment in project settings to keep alignment with category three dots */ + margin-right: 0px; } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutDark.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutDark.uss index 9aa3af97..d77be284 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutDark.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutDark.uss @@ -3,7 +3,7 @@ border-color: #1f1f1f; } -.header-foldout > Toggle +.unity-foldout__toggle { background-color: #323232; } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutLight.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutLight.uss index 0c0cdf68..20840862 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutLight.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/HeaderFoldoutLight.uss @@ -3,7 +3,7 @@ border-color: #999999; } -.header-foldout > Toggle +.unity-foldout__toggle { background-color: #d3d3d3; } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewer.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewer.uss index c55af2fc..01d91547 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewer.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewer.uss @@ -12,6 +12,10 @@ --dependency-block-height: 26px; --dependency-block-width: var(--pass-width); --hover-overlay-offset-top: 204px; + --action-border-width: 13px; + --action-border-height: var(--action-border-width); + --action-width: 12px; + --action-height: var(--action-width); --side-panel-width: 380px; --side-panel-pass-title-width: 330px; /* adjust if changing --side-panel-width */ @@ -607,4 +611,31 @@ ScrollView TextElement { margin-bottom: 12px; } +.dependency-block-load-action { + width: var(--action-width); + height: var(--action-height); + position: absolute; + top: 0; + left: 0; +} + +.dependency-block-load-action-border { + width: var(--action-border-width); + height: var(--action-border-height); + color: var(--load-action-border-color); +} +.dependency-block-store-action { + width: var(--action-width); + height: var(--action-height); + position: absolute; + rotate: 180deg; + bottom: 0; + right: 0; +} + +.dependency-block-store-action-border { + width: var(--action-border-width); + height: var(--action-border-height); + color: var(--store-action-border-color); +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerDark.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerDark.uss index 182870c4..e634ee12 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerDark.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerDark.uss @@ -19,6 +19,8 @@ --side-panel-background-color: #383838; --side-panel-item-border-color: #666666; --side-panel-secondary-text-color: #808080; + --load-action-border-color: #555555; + --store-action-border-color: #555555; } #capture-button { @@ -49,6 +51,10 @@ background-image: url("../Icons/RenderGraphViewer/d_Texture@2x.png"); } +.resource-icon--memoryless-texture { + background-image: url("../Icons/RenderGraphViewer/d_MemorylessTexture@2x.png"); +} + .resource-icon--buffer { background-image: url("../Icons/RenderGraphViewer/d_Buffer@2x.png"); } @@ -78,3 +84,31 @@ .custom-foldout-arrow > Toggle > VisualElement:hover #unity-checkmark { -unity-background-image-tint-color: white; } + +.load-action-load { + color: #9deb24; +} + +.load-action-clear { + color: cornflowerblue; +} + +.load-action-dont-care { + color: lightslategray; +} + +.store-action-store { + color: darkred; +} + +.store-action-resolve { + color: lightseagreen; +} + +.store-action-store-resolve { + color: lightsalmon; +} + +.store-action-dont-care { + color: lightslategray; +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerLight.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerLight.uss index 17e663c3..cd4c9aa0 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerLight.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewerLight.uss @@ -19,6 +19,8 @@ --side-panel-background-color: #cbcbcb; --side-panel-item-border-color: #666666; --side-panel-secondary-text-color: #707070; + --load-action-border-color: #555555; + --store-action-border-color: #555555; } #capture-button { @@ -49,6 +51,10 @@ background-image: url("../Icons/RenderGraphViewer/Texture@2x.png"); } +.resource-icon--memoryless-texture { + background-image: url("../Icons/RenderGraphViewer/MemorylessTexture@2x.png"); +} + .resource-icon--buffer { background-image: url("../Icons/RenderGraphViewer/Buffer@2x.png"); } @@ -82,3 +88,31 @@ .custom-foldout-arrow > Toggle > VisualElement:hover #unity-checkmark { -unity-background-image-tint-color: grey; } + +.load-action-load { + color: #9deb24; +} + +.load-action-clear { + color: cornflowerblue; +} + +.load-action-dont-care { + color: lightslategray; +} + +.store-action-store { + color: darkred; +} + +.store-action-resolve { + color: lightseagreen; +} + +.store-action-store-resolve { + color: lightsalmon; +} + +.store-action-dont-care { + color: lightslategray; +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/UXML/RenderGraphViewer.uxml b/Packages/com.unity.render-pipelines.core/Editor/UXML/RenderGraphViewer.uxml index bc58e878..e9997269 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/UXML/RenderGraphViewer.uxml +++ b/Packages/com.unity.render-pipelines.core/Editor/UXML/RenderGraphViewer.uxml @@ -6,6 +6,7 @@ + diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/Drawers/FloatParameterDrawer.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/Drawers/FloatParameterDrawer.cs index 2ec1dcf6..c334414f 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/Drawers/FloatParameterDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/Drawers/FloatParameterDrawer.cs @@ -108,6 +108,8 @@ namespace UnityEditor.Rendering [VolumeParameterDrawer(typeof(FloatRangeParameter))] sealed class FloatRangeParameterDrawer : VolumeParameterDrawer { + public override float GetElementHeight(SerializedDataParameter parameter) => EditorGUIUtility.singleLineHeight; + public override bool OnGUI(SerializedDataParameter parameter, GUIContent title) { var value = parameter.value; @@ -118,16 +120,15 @@ namespace UnityEditor.Rendering var o = parameter.GetObjectRef(); var v = value.vector2Value; - // The layout system breaks alignement when mixing inspector fields with custom layouted + // The layout system breaks alignment when mixing inspector fields with custom layouted // fields as soon as a scrollbar is needed in the inspector, so we'll do the layout // manually instead const int kFloatFieldWidth = 50; const int kSeparatorWidth = 5; float indentOffset = EditorGUI.indentLevel * 15f; var lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight); - lineRect.xMin += 4f; lineRect.y += 2f; - var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height); + var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset + 2f, lineRect.height); var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height); var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y, lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height); var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y, kFloatFieldWidth + indentOffset, lineRect.height); 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 1792269b..5044a6bd 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs @@ -122,7 +122,7 @@ namespace UnityEditor.Rendering /// /// Override this property if your editor makes use of the "Additional Properties" feature. /// - public virtual bool hasAdditionalProperties => volumeComponent.parameterList.Count != m_VolumeNotAdditionalParameters.Count; + public virtual bool hasAdditionalProperties => volumeComponent.parameterList.Length != m_VolumeNotAdditionalParameters.Count; /// /// Set to true to show additional properties. @@ -503,7 +503,7 @@ namespace UnityEditor.Rendering internal bool AreAllOverridesTo(bool state) { - for (int i = 0; i < volumeComponent.parameterList.Count; ++i) + for (int i = 0; i < volumeComponent.parameterList.Length; ++i) { if (volumeComponent.parameterList[i].overrideState != state) return false; @@ -725,9 +725,23 @@ namespace UnityEditor.Rendering /// /// The property to draw the override checkbox for protected void DrawOverrideCheckbox(SerializedDataParameter property) + { + DrawOverrideCheckbox(property, null); + } + + /// + /// Draws the override checkbox used by a property in the editor. + /// + /// The property to draw the override checkbox for + /// The instance responsible for + /// drawing the . This is used to get the correct element height + /// via . Can be null, in which + /// case the default property height is used. + protected void DrawOverrideCheckbox(SerializedDataParameter property, VolumeParameterDrawer drawer) { // Create a rect the height + vspacing of the property that is being overriden - float height = EditorGUI.GetPropertyHeight(property.value) + EditorGUIUtility.standardVerticalSpacing; + float elementHeight = drawer?.GetElementHeight(property) ?? EditorGUI.GetPropertyHeight(property.value); + float height = elementHeight + EditorGUIUtility.standardVerticalSpacing; var overrideRect = GUILayoutUtility.GetRect(Styles.k_AllText, CoreEditorStyles.miniLabelButton, GUILayout.Height(height), GUILayout.Width(Styles.overrideCheckboxWidth + Styles.overrideCheckboxOffset), GUILayout.ExpandWidth(false)); @@ -838,7 +852,7 @@ namespace UnityEditor.Rendering { EditorGUILayout.BeginHorizontal(); if (editor.enableOverrides) - editor.DrawOverrideCheckbox(property); + editor.DrawOverrideCheckbox(property, drawer); disabledScope = new EditorGUI.DisabledScope(!property.overrideState.boolValue); } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeParameterDrawer.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeParameterDrawer.cs index a463ad4f..98902fd1 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeParameterDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeParameterDrawer.cs @@ -74,6 +74,16 @@ namespace UnityEditor.Rendering /// otherwise public virtual bool IsAutoProperty() => true; + /// + /// Gets the vertical space (height) required to draw the parameter's GUI. Override this + /// method if your custom GUI implemented in requires a specific height + /// different from the default property height. + /// + /// The parameter for which to calculate the height. + /// The required height in pixels. The default implementation returns + /// EditorGUI.GetPropertyHeight(parameter.value). + public virtual float GetElementHeight(SerializedDataParameter parameter) => EditorGUI.GetPropertyHeight(parameter.value); + /// /// Draws the parameter in the editor. If the input parameter is invalid you should return /// false so that Unity displays the default editor for this parameter. diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeProfileFactory.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeProfileFactory.cs index ee1245b6..9c648798 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeProfileFactory.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeProfileFactory.cs @@ -12,7 +12,7 @@ namespace UnityEditor.Rendering /// public static class VolumeProfileFactory { - [MenuItem("Assets/Create/Rendering/Volume Profile", priority = 201)] + [MenuItem("Assets/Create/Rendering/Volume Profile", priority = 10)] static void CreateVolumeProfile() { ProjectWindowUtil.StartNameEditingIfProjectWindowExists( diff --git a/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs b/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs index 96162f18..b2216854 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs @@ -9,3 +9,4 @@ using System.Runtime.CompilerServices; // Smoke test project visibility [assembly: InternalsVisibleTo("SRPSmoke.Runtime.Tests")] [assembly: InternalsVisibleTo("SRPSmoke.Editor.Tests")] +[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")] diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraSwitcher.cs b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraSwitcher.cs index 8da9abdb..7c839d88 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraSwitcher.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraSwitcher.cs @@ -104,14 +104,10 @@ namespace UnityEngine.Rendering if (m_CurrentCamera != null) { // If we witch back to the original camera, put back the transform in it. - if (m_CurrentCamera == m_OriginalCamera) - { - m_OriginalCamera.transform.position = m_OriginalCameraPosition; - m_OriginalCamera.transform.rotation = m_OriginalCameraRotation; - } - - transform.position = m_CurrentCamera.transform.position; - transform.rotation = m_CurrentCamera.transform.rotation; + if (m_CurrentCamera == m_OriginalCamera) + m_OriginalCamera.transform.SetPositionAndRotation(m_OriginalCameraPosition, m_OriginalCameraRotation); + + transform.SetPositionAndRotation(m_CurrentCamera.transform.position, m_CurrentCamera.transform.rotation); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Camera/FreeCamera.cs b/Packages/com.unity.render-pipelines.core/Runtime/Camera/FreeCamera.cs index 0b9f74f6..e3b1f3f2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Camera/FreeCamera.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Camera/FreeCamera.cs @@ -194,9 +194,9 @@ namespace UnityEngine.Rendering float moveSpeed = Time.deltaTime * m_MoveSpeed; if (fire1 || leftShiftBoost && leftShift) moveSpeed *= m_Turbo; - transform.position += transform.forward * moveSpeed * inputVertical; - transform.position += transform.right * moveSpeed * inputHorizontal; - transform.position += Vector3.up * moveSpeed * inputYAxis; + transform.position += transform.forward * (moveSpeed * inputVertical) + + transform.right * (moveSpeed * inputHorizontal) + + Vector3.up * (moveSpeed * inputYAxis); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs b/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs index cfbdae31..ef5a8c35 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs @@ -228,7 +228,7 @@ namespace UnityEngine.Rendering /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1. public int FindIndex(int startIndex, int count, Predicate match) { - for (int i = startIndex; i < size; ++i) + for (int i = startIndex; i < size && count > 0; ++i, --count) { if (match(m_Array[i])) { @@ -238,6 +238,16 @@ namespace UnityEngine.Rendering return -1; } + /// + /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray. + /// + /// The Predicate delegate that defines the conditions of the element to search for. + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1. + public int FindIndex(Predicate match) + { + return FindIndex(0, size, match); + } + /// /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray that starts at the specified index and contains the specified number of elements. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Common/ObservableList.cs b/Packages/com.unity.render-pipelines.core/Runtime/Common/ObservableList.cs index 02794b91..cf85070f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Common/ObservableList.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Common/ObservableList.cs @@ -45,7 +45,8 @@ namespace UnityEngine.Rendering /// Type of the list. public class ObservableList : IList { - IList m_List; + List m_List; + private readonly Comparison m_Comparison; /// /// Added item event. @@ -98,18 +99,23 @@ namespace UnityEngine.Rendering /// Constructor. /// /// Allocation size. - public ObservableList(int capacity) + /// The comparision if you want the list to be sorted + public ObservableList(int capacity, Comparison comparison = null) { m_List = new List(capacity); + m_Comparison = comparison; } /// /// Constructor. /// /// Input list. - public ObservableList(IEnumerable collection) + /// The comparision if you want the list to be sorted + public ObservableList(IEnumerable collection, Comparison comparison = null) { m_List = new List(collection); + m_Comparison = comparison; + Sort(); // Make sure the given list is sorted } void OnEvent(ListChangedEventHandler e, int index, T item) @@ -145,6 +151,7 @@ namespace UnityEngine.Rendering public void Add(T item) { m_List.Add(item); + Sort(); OnEvent(ItemAdded, m_List.IndexOf(item), item); } @@ -166,6 +173,7 @@ namespace UnityEngine.Rendering public void Insert(int index, T item) { m_List.Insert(index, item); + Sort(); OnEvent(ItemAdded, index, item); } @@ -248,5 +256,13 @@ namespace UnityEngine.Rendering { return GetEnumerator(); } + + private void Sort() + { + if (m_Comparison != null) + { + m_List.Sort(m_Comparison); + } + } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs index fb344294..d272c1a0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs @@ -138,6 +138,11 @@ namespace UnityEngine.Rendering /// public virtual void Reset() { + foreach (IDebugDisplaySettingsData setting in m_Settings) + { + setting.Reset(); + } + m_Settings.Clear(); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs index 76c6dc06..87296a7f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; + +#if UNITY_EDITOR using UnityEditor; +#endif namespace UnityEngine.Rendering { @@ -12,37 +14,273 @@ namespace UnityEngine.Rendering public class DebugDisplaySettingsVolume : IDebugDisplaySettingsData { /// Current volume debug settings. + [Obsolete("This property has been obsoleted and will be removed in a future version. #from(6000.2)", false)] public IVolumeDebugSettings volumeDebugSettings { get; } + private int m_SelectedComponentIndex = -1; + + /// Current volume component to debug. + public int selectedComponent + { + get => m_SelectedComponentIndex; + set + { + if (value != m_SelectedComponentIndex) + { + m_SelectedComponentIndex = value; + OnSelectionChanged(); + } + } + } + + private void DestroyVolumeInterpolatedResults() + { + if (m_VolumeInterpolatedResults != null) + ScriptableObject.DestroyImmediate(m_VolumeInterpolatedResults); + } + + /// Type of the current component to debug. + public Type selectedComponentType + { + get => selectedComponent > 0 ? volumeComponentsPathAndType[selectedComponent - 1].Item2 : null; + set + { + var index = volumeComponentsPathAndType.FindIndex(t => t.Item2 == value); + if (index != -1) + selectedComponent = index + 1; + } + } + + /// List of Volume component types. + public List<(string, Type)> volumeComponentsPathAndType => VolumeManager.instance.GetVolumeComponentsForDisplay(GraphicsSettings.currentRenderPipelineAssetType); + + private Camera m_SelectedCamera; + + /// Current camera to debug. + public Camera selectedCamera + { + get + { +#if UNITY_EDITOR + // By default pick the one scene camera + if (m_SelectedCamera == null && SceneView.lastActiveSceneView != null) + { + var sceneCamera = SceneView.lastActiveSceneView.camera; + if (sceneCamera != null) + m_SelectedCamera = sceneCamera; + } +#endif + + return m_SelectedCamera; + } + set + { + if (value != null && value != m_SelectedCamera) + { + m_SelectedCamera = value; + OnSelectionChanged(); + } + } + } + + private void OnSelectionChanged() + { + ClearInterpolationData(); + DestroyVolumeInterpolatedResults(); + } + + VolumeComponent m_VolumeInterpolatedResults; + private bool m_StoreStackInterpolatedValues; + private ObservableList m_InfluenceVolumes = new (); + private List<(Volume volume, float weight)> m_VolumesWeights = new (); + + private void ClearInterpolationData() + { + m_VolumesWeights.Clear(); + } + + static bool AreVolumesChanged(ObservableList influenceVolumes, List<(Volume volume, float weight)> volumesWeights) + { + // First, check if the lists have the same number of elements + if (influenceVolumes.Count != volumesWeights.Count) + return true; + + // Sequence Equals + for (int i = 0; i < influenceVolumes.Count; i++) + { + if (influenceVolumes[i] != volumesWeights[i].volume) + return true; + } + + // If all checks pass, the lists are the same (in terms of both content and order) + return false; + } + + private void OnBeginVolumeStackUpdate(VolumeStack stack, Camera camera) + { + if (camera == selectedCamera) + { + ClearInterpolationData(); + m_StoreStackInterpolatedValues = selectedCamera != null && selectedComponentType != null; + } + } + + private void OnEndVolumeStackUpdate(VolumeStack stack, Camera camera) + { + if (m_StoreStackInterpolatedValues) + { + if (AreVolumesChanged(m_InfluenceVolumes, m_VolumesWeights)) + { + m_InfluenceVolumes.Clear(); + foreach (var pair in m_VolumesWeights) + m_InfluenceVolumes.Add(pair.volume); + } + + // Copy the results of the interpolation into our resulVolumeComponent + var componentInStack = stack.GetComponent(selectedComponentType); + + for (int i = 0; i < componentInStack.parameters.Count; ++i) + { + resultVolumeComponent.parameters[i].SetValue(componentInStack.parameters[i]); + } + + m_StoreStackInterpolatedValues = false; + } + } + + private void OnVolumeStackInterpolated(VolumeStack stack, Volume volume, float interpolationFactor) + { + if (m_StoreStackInterpolatedValues) + { + m_VolumesWeights.Add((volume, interpolationFactor)); + } + } + + /// + /// Obtains the volume weight + /// + /// + /// The weight of the volume + public float GetVolumeWeight(Volume volume) + { + // Try to get the weight associated with the volume + // If the volume is not found, return a default value (e.g., 0.0f) + if (m_VolumesWeights.Count == 0) + return 0.0f; + + foreach (var pair in m_VolumesWeights) + { + if (volume == pair.volume) + return pair.weight; + } + + return 0.0f; + } + + /// + /// Gets the Volumes List for the current camera and selected volume component + /// + /// The list of influenced volumes + public ObservableList GetVolumesList() + { + return m_InfluenceVolumes; + } + + + void IDebugDisplaySettingsData.Reset() + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + VolumeManager.instance.overrideVolumeStackData -= OnVolumeStackInterpolated; + VolumeManager.instance.beginVolumeStackUpdate -= OnBeginVolumeStackUpdate; + VolumeManager.instance.endVolumeStackUpdate -= OnEndVolumeStackUpdate; + VolumeManager.instance.renderingDebuggerAttached = false; +#endif + + ClearInterpolationData(); + DestroyVolumeInterpolatedResults(); + } + /// /// Constructor with the settings /// /// The volume debug settings object used for configuration. + [Obsolete("This constructor has been obsoleted and will be removed in a future version. #from(6000.2)", false)] public DebugDisplaySettingsVolume(IVolumeDebugSettings volumeDebugSettings) + : this() { this.volumeDebugSettings = volumeDebugSettings; } + /// + /// Constructor with the settings + /// + public DebugDisplaySettingsVolume() + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + VolumeManager.instance.overrideVolumeStackData += OnVolumeStackInterpolated; + VolumeManager.instance.beginVolumeStackUpdate += OnBeginVolumeStackUpdate; + VolumeManager.instance.endVolumeStackUpdate += OnEndVolumeStackUpdate; +#endif + } + internal int volumeComponentEnumIndex; + internal VolumeComponent resultVolumeComponent + { + get + { + if (m_VolumeInterpolatedResults == null) + m_VolumeInterpolatedResults = ScriptableObject.CreateInstance(selectedComponentType) as VolumeComponent; - internal Dictionary debugState = new Dictionary(); + return m_VolumeInterpolatedResults; + } + } + + internal static string ExtractResult(VolumeParameter param) + { + if (param == null) + return Strings.parameterNotCalculated; + + var paramType = param.GetType(); + + var property = paramType.GetProperty("value"); + if (property == null) + return "-"; + + var value = property.GetValue(param); + var propertyType = property.PropertyType; + if (value == null || value.Equals(null)) + return Strings.none + $" ({propertyType.Name})"; + + var toString = propertyType.GetMethod("ToString", Type.EmptyTypes); + if ((toString == null) || (toString.DeclaringType == typeof(object)) || (toString.DeclaringType == typeof(Object))) + { + // Check if the parameter has a name + var nameProp = property.PropertyType.GetProperty("name"); + if (nameProp == null) + return Strings.debugViewNotSupported; + + var valueString = $"{nameProp.GetValue(value)}"; + return valueString ?? Strings.none; + } + + return value.ToString(); + } static class Styles { public static readonly GUIContent none = new GUIContent("None"); - public static readonly GUIContent editorCamera = new GUIContent("Editor Camera"); } static class Strings { + public static readonly string cameraNeedsRendering = "Values might not be fully updated if the camera you are inspecting is not rendered."; public static readonly string none = "None"; - public static readonly string camera = "Camera"; public static readonly string parameter = "Parameter"; public static readonly string component = "Component"; public static readonly string debugViewNotSupported = "N/A"; - public static readonly string parameterNotOverrided = "-"; public static readonly string volumeInfo = "Volume Info"; public static readonly string gameObject = "GameObject"; + public static readonly string priority = "Priority"; public static readonly string resultValue = "Result"; public static readonly string resultValueTooltip = "The interpolated result value of the parameter. This value is used to render the camera."; public static readonly string globalDefaultValue = "Graphics Settings"; @@ -52,6 +290,7 @@ namespace UnityEngine.Rendering public static readonly string global = "Global"; public static readonly string local = "Local"; public static readonly string volumeProfile = "Volume Profile"; + public static readonly string parameterNotCalculated = "N/A"; } const string k_PanelTitle = "Volume"; @@ -74,7 +313,7 @@ namespace UnityEngine.Rendering var componentNames = new List() { Styles.none }; var componentValues = new List() { componentIndex++ }; - var volumesAndTypes = VolumeManager.instance.GetVolumeComponentsForDisplay(GraphicsSettings.currentRenderPipelineAssetType); + var volumesAndTypes = panel.data.volumeComponentsPathAndType; foreach (var type in volumesAndTypes) { componentNames.Add(new GUIContent() { text = type.Item1 }); @@ -84,8 +323,8 @@ namespace UnityEngine.Rendering return new DebugUI.EnumField { displayName = Strings.component, - getter = () => panel.data.volumeDebugSettings.selectedComponent, - setter = value => panel.data.volumeDebugSettings.selectedComponent = value, + getter = () => panel.data.selectedComponent, + setter = value => panel.data.selectedComponent = value, enumNames = componentNames.ToArray(), enumValues = componentValues.ToArray(), getIndex = () => panel.data.volumeComponentEnumIndex, @@ -96,25 +335,22 @@ namespace UnityEngine.Rendering public static DebugUI.ObjectPopupField CreateCameraSelector(SettingsPanel panel, Action, Object> refresh) { - return new DebugUI.ObjectPopupField + return new DebugUI.CameraSelector() { - displayName = Strings.camera, - getter = () => panel.data.volumeDebugSettings.selectedCamera, - setter = value => - { - var c = panel.data.volumeDebugSettings.cameras.ToArray(); - panel.data.volumeDebugSettings.selectedCameraIndex = Array.IndexOf(c, value as Camera); - }, - getObjects = () => panel.data.volumeDebugSettings.cameras, + getter = () => panel.data.selectedCamera, + setter = value => panel.data.selectedCamera = value as Camera, onValueChanged = refresh }; } - static DebugUI.Widget CreateVolumeParameterWidget(string name, bool isResultParameter, VolumeParameter param, Func isHiddenCallback = null) + internal static DebugUI.Widget CreateVolumeParameterWidget(string name, bool isResultParameter, VolumeParameter param) { #if UNITY_EDITOR || DEVELOPMENT_BUILD if (param != null) { + Func isHiddenCallback = isResultParameter ? + () => false : + () => !param.overrideState; var parameterType = param.GetType(); if (parameterType == typeof(ColorParameter)) { @@ -129,6 +365,31 @@ namespace UnityEngine.Rendering isHiddenCallback = isHiddenCallback }; } + else if (parameterType.BaseType.IsGenericType && parameterType.BaseType.GetGenericArguments().Length > 0) + { + // Get the generic type argument, e.g., in VolumeParameter + var genericArgument = parameterType.BaseType.GetGenericArguments()[0]; + + // Check if the argument is a UnityEngine.Object or derived type + if (typeof(Object).IsAssignableFrom(genericArgument)) + { + return new DebugUI.ObjectField() + { + displayName = name, + getter = () => + { + var property = parameterType.GetProperty("value"); + if (property == null) + return null; + + var value = property.GetValue(param); + return value as Object; + + }, + isHiddenCallback = isHiddenCallback + }; + } + } var typeInfo = parameterType.GetTypeInfo(); var genericArguments = typeInfo.BaseType.GenericTypeArguments; @@ -138,48 +399,20 @@ namespace UnityEngine.Rendering { displayName = name, getter = () => (Object[])parameterType.GetProperty("value").GetValue(param, null), - type = parameterType + type = parameterType, + isHiddenCallback = isHiddenCallback }; } return new DebugUI.Value() { displayName = name, - getter = () => - { - var property = param.GetType().GetProperty("value"); - if (property == null) - return "-"; - - if (isResultParameter || param.overrideState) - { - var value = property.GetValue(param); - var propertyType = property.PropertyType; - if (value == null || value.Equals(null)) - return Strings.none + $" ({propertyType.Name})"; - - var toString = propertyType.GetMethod("ToString", Type.EmptyTypes); - if ((toString == null) || (toString.DeclaringType == typeof(object)) || (toString.DeclaringType == typeof(UnityEngine.Object))) - { - // Check if the parameter has a name - var nameProp = property.PropertyType.GetProperty("name"); - if (nameProp == null) - return Strings.debugViewNotSupported; - - var valueString = nameProp.GetValue(value); - return valueString ?? Strings.none; - } - - return value.ToString(); - } - - return Strings.parameterNotOverrided; - }, + getter = () => ExtractResult(param), isHiddenCallback = isHiddenCallback }; } #endif - return new DebugUI.Value(); + return new DebugUI.Value() { displayName = name, getter = () => Strings.parameterNotCalculated, }; } static DebugUI.Value s_EmptyDebugUIValue = new DebugUI.Value { getter = () => string.Empty }; @@ -207,14 +440,11 @@ namespace UnityEngine.Rendering { List chain = new List(); - Type selectedType = data.volumeDebugSettings.selectedComponentType; - if (selectedType == null) + Type selectedType = data.selectedComponentType; + if (data.selectedCamera == null || selectedType == null) return chain; - var volumeManager = VolumeManager.instance; - var stack = data.volumeDebugSettings.selectedCameraVolumeStack ?? volumeManager.stack; - var stackComponent = stack.GetComponent(selectedType); - if (stackComponent == null) + if (data.resultVolumeComponent == null) return chain; var result = new VolumeParameterChain() @@ -224,15 +454,17 @@ namespace UnityEngine.Rendering name = Strings.resultValue, tooltip = Strings.resultValueTooltip, }, - volumeComponent = stackComponent, + volumeComponent = data.resultVolumeComponent }; chain.Add(result); - // Add volume components that override default values - var volumes = data.volumeDebugSettings.GetVolumes(); - foreach (var volume in volumes) + // Add volume components that override the default values. + // Iterate in reverse order to display the last interpolated Volume (most relevant) next to the result in the table view. + var volumes = data.GetVolumesList(); + for (int i = volumes.Count - 1; i >= 0; i--) { + var volume = volumes[i]; var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile; var overrideComponent = GetSelectedVolumeComponent(profile, selectedType); if (overrideComponent != null) @@ -253,9 +485,9 @@ namespace UnityEngine.Rendering } // Add custom default profiles - if (volumeManager.customDefaultProfiles != null) + if (VolumeManager.instance.customDefaultProfiles != null) { - foreach (var customProfile in volumeManager.customDefaultProfiles) + foreach (var customProfile in VolumeManager.instance.customDefaultProfiles) { var customProfileComponent = GetSelectedVolumeComponent(customProfile, selectedType); if (customProfileComponent != null) @@ -276,9 +508,9 @@ namespace UnityEngine.Rendering } // Add Quality Settings - if (volumeManager.globalDefaultProfile != null) + if (VolumeManager.instance.qualityDefaultProfile != null) { - var qualitySettingsComponent = GetSelectedVolumeComponent(volumeManager.qualityDefaultProfile, selectedType); + var qualitySettingsComponent = GetSelectedVolumeComponent(VolumeManager.instance.qualityDefaultProfile, selectedType); if (qualitySettingsComponent != null) { var overrideVolume = new VolumeParameterChain() @@ -288,7 +520,7 @@ namespace UnityEngine.Rendering name = Strings.qualityLevelValue, tooltip = Strings.qualityLevelValueTooltip, }, - volumeProfile = volumeManager.qualityDefaultProfile, + volumeProfile = VolumeManager.instance.qualityDefaultProfile, volumeComponent = qualitySettingsComponent, }; chain.Add(overrideVolume); @@ -296,9 +528,9 @@ namespace UnityEngine.Rendering } // Add Graphics Settings - if (volumeManager.globalDefaultProfile != null) + if (VolumeManager.instance.globalDefaultProfile != null) { - var graphicsSettingsComponent = GetSelectedVolumeComponent(volumeManager.globalDefaultProfile, selectedType); + var graphicsSettingsComponent = GetSelectedVolumeComponent(VolumeManager.instance.globalDefaultProfile, selectedType); if (graphicsSettingsComponent != null) { var overrideVolume = new VolumeParameterChain() @@ -308,7 +540,7 @@ namespace UnityEngine.Rendering name = Strings.globalDefaultValue, tooltip = Strings.globalDefaultValueTooltip, }, - volumeProfile = volumeManager.globalDefaultProfile, + volumeProfile = VolumeManager.instance.globalDefaultProfile, volumeComponent = graphicsSettingsComponent, }; chain.Add(overrideVolume); @@ -320,11 +552,21 @@ namespace UnityEngine.Rendering public static DebugUI.Table CreateVolumeTable(DebugDisplaySettingsVolume data) { + // Function for updating the attach state and also checking if the table should be visible + Func hiddenCallback = () => + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + VolumeManager.instance.renderingDebuggerAttached = data.selectedComponent > 0 && data.selectedCamera != null; + return !VolumeManager.instance.renderingDebuggerAttached; +#else + return true; +#endif + }; var table = new DebugUI.Table() { displayName = Strings.parameter, isReadOnly = true, - isHiddenCallback = () => data.volumeDebugSettings.selectedComponent == 0 + isHiddenCallback = hiddenCallback, }; var resolutionChain = GetResolutionChain(data); @@ -334,67 +576,9 @@ namespace UnityEngine.Rendering GenerateTableRows(table, resolutionChain); GenerateTableColumns(table, data, resolutionChain); - float timer = 0.0f, refreshRate = 0.2f; - var volumes = data.volumeDebugSettings.GetVolumes(); - table.isHiddenCallback = () => - { - timer += Time.deltaTime; - if (timer >= refreshRate) - { - if (data.volumeDebugSettings.selectedCamera != null) - { - SetTableColumnVisibility(data, table); - - var newVolumes = data.volumeDebugSettings.GetVolumes(); - if (!volumes.SequenceEqual(newVolumes)) - { - volumes = newVolumes; - DebugManager.instance.ReDrawOnScreenDebug(); - } - } - - timer = 0.0f; - } - return false; - }; - return table; } - private static void SetTableColumnVisibility(DebugDisplaySettingsVolume data, DebugUI.Table table) - { - var newResolutionChain = GetResolutionChain(data); - for (int i = 1; i < newResolutionChain.Count; i++) // We always skip the interpolated stack that is in index 0 - { - bool visible = true; - if (newResolutionChain[i].volume != null) - { - visible = data.volumeDebugSettings.VolumeHasInfluence(newResolutionChain[i].volume); - } - else - { - visible = newResolutionChain[i].volumeComponent.active; - - if (visible) - { - bool atLeastOneParameterIsOverriden = false; - foreach (var parameter in newResolutionChain[i].volumeComponent.parameterList) - { - if (parameter.overrideState == true) - { - atLeastOneParameterIsOverriden = true; - break; - } - } - - visible &= atLeastOneParameterIsOverriden; - } - } - - table.SetColumnVisibility(i, visible); - } - } - private static void GenerateTableColumns(DebugUI.Table table, DebugDisplaySettingsVolume data, List resolutionChain) { for (int i = 0; i < resolutionChain.Count; ++i) @@ -410,12 +594,20 @@ namespace UnityEngine.Rendering getter = () => { var scope = chain.volume.isGlobal ? Strings.global : Strings.local; - var weight = data.volumeDebugSettings.GetVolumeWeight(chain.volume); - return scope + " (" + (weight * 100f) + "%)"; + var weight = data.GetVolumeWeight(chain.volume); + if (chain.volumeComponent.active) + return $"{scope} ({(weight * 100f):F2}%)"; + else + return $"{scope} (disabled)"; }, refreshRate = 0.2f }); ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(new DebugUI.ObjectField() { displayName = string.Empty, getter = () => chain.volume }); + ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(new DebugUI.Value() + { + nameAndTooltip = chain.nameAndTooltip, + getter = () => chain.volume.priority + }); } else { @@ -425,25 +617,27 @@ namespace UnityEngine.Rendering getter = () => string.Empty }); ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(s_EmptyDebugUIValue); + ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(s_EmptyDebugUIValue); } - ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(chain.volumeProfile != null ? new DebugUI.ObjectField() { displayName = string.Empty, getter = () => chain.volumeProfile } : + ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(chain.volumeProfile != null ? + new DebugUI.ObjectField() { displayName = string.Empty, getter = () => chain.volumeProfile } : s_EmptyDebugUIValue); ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(s_EmptyDebugUIValue); bool isResultParameter = i == 0; - for (int j = 0; j < chain.volumeComponent.parameterList.Count; ++j) + for (int j = 0; j < chain.volumeComponent.parameterList.Length; ++j) { var parameter = chain.volumeComponent.parameterList[j]; - ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add(CreateVolumeParameterWidget(chain.nameAndTooltip.name, isResultParameter, parameter)); + ((DebugUI.Table.Row)table.children[++iRowIndex]).children.Add( + CreateVolumeParameterWidget(chain.nameAndTooltip.name, isResultParameter, parameter)); } } } private static void GenerateTableRows(DebugUI.Table table, List resolutionChain) { - // First row for volume info var volumeInfoRow = new DebugUI.Table.Row() { displayName = Strings.volumeInfo, @@ -452,7 +646,6 @@ namespace UnityEngine.Rendering table.children.Add(volumeInfoRow); - // Second row, links to volume gameobjects var gameObjectRow = new DebugUI.Table.Row() { displayName = Strings.gameObject, @@ -460,13 +653,20 @@ namespace UnityEngine.Rendering table.children.Add(gameObjectRow); - // Third row, links to volume profile assets + var priorityRow = new DebugUI.Table.Row() + { + displayName = Strings.priority, + }; + + table.children.Add(priorityRow); + var volumeProfileRow = new DebugUI.Table.Row() { displayName = Strings.volumeProfile, }; table.children.Add(volumeProfileRow); + var separatorRow = new DebugUI.Table.Row() { displayName = string.Empty , @@ -475,7 +675,7 @@ namespace UnityEngine.Rendering table.children.Add(separatorRow); var results = resolutionChain[0].volumeComponent; - for (int i = 0; i < results.parameterList.Count; ++i) + for (int i = 0; i < results.parameterList.Length; ++i) { var parameter = results.parameterList[i]; #if UNITY_EDITOR || DEVELOPMENT_BUILD @@ -494,13 +694,40 @@ namespace UnityEngine.Rendering [DisplayInfo(name = k_PanelTitle, order = int.MaxValue)] internal class SettingsPanel : DebugDisplaySettingsPanel { + // When we are moving the scene camera, we want the editor window to be repainted too + public override DebugUI.Flags Flags => DebugUI.Flags.EditorForceUpdate; + + public override void Dispose() + { + base.Dispose(); + + data.GetVolumesList().ItemAdded -= OnVolumeInfluenceChanged; + data.GetVolumesList().ItemRemoved -= OnVolumeInfluenceChanged; + } + public SettingsPanel(DebugDisplaySettingsVolume data) : base(data) { AddWidget(WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh())); AddWidget(WidgetFactory.CreateComponentSelector(this, (_, __) => Refresh())); - m_VolumeTable = WidgetFactory.CreateVolumeTable(m_Data); + + Func hiddenCallback = () => data.selectedCamera == null || data.selectedComponent <= 0; + AddWidget(new DebugUI.MessageBox() + { + displayName = Strings.cameraNeedsRendering, + style = DebugUI.MessageBox.Style.Warning, + isHiddenCallback = hiddenCallback, + }); + m_VolumeTable = WidgetFactory.CreateVolumeTable(data); AddWidget(m_VolumeTable); + data.GetVolumesList().ItemAdded += OnVolumeInfluenceChanged; + data.GetVolumesList().ItemRemoved += OnVolumeInfluenceChanged; + } + + private void OnVolumeInfluenceChanged(ObservableList sender, ListChangedEventArgs e) + { + Refresh(); + DebugManager.instance.ReDrawOnScreenDebug(); } DebugUI.Table m_VolumeTable = null; @@ -511,22 +738,22 @@ namespace UnityEngine.Rendering return; bool needsRefresh = false; - if (m_VolumeTable != null) + if (m_Data.selectedComponent > 0 && m_Data.selectedCamera != null) { needsRefresh = true; - panel.children.Remove(m_VolumeTable); - } + var volumeTable = WidgetFactory.CreateVolumeTable(m_Data); - if (m_Data.volumeDebugSettings.selectedComponent > 0 && m_Data.volumeDebugSettings.selectedCamera != null) - { - needsRefresh = true; - m_VolumeTable = WidgetFactory.CreateVolumeTable(m_Data); - AddWidget(m_VolumeTable); - panel.children.Add(m_VolumeTable); + m_VolumeTable.children.Clear(); + foreach (var row in volumeTable.children) + { + m_VolumeTable.children.Add(row); + } } if (needsRefresh) + { DebugManager.instance.ReDrawOnScreenDebug(); + } } } @@ -541,7 +768,6 @@ namespace UnityEngine.Rendering { return new SettingsPanel(this); } - #endregion } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugFrameTiming.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugFrameTiming.cs index 3a48853e..8f7c7557 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugFrameTiming.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugFrameTiming.cs @@ -79,7 +79,6 @@ namespace UnityEngine.Rendering list.Add(new DebugUI.Foldout() { displayName = "Frame Stats", - isHeader = true, opened = true, columnLabels = new string[] { "Avg", "Min", "Max" }, children = @@ -150,7 +149,6 @@ namespace UnityEngine.Rendering list.Add(new DebugUI.Foldout { displayName = "Bottlenecks", - isHeader = true, children = { #if UNITY_EDITOR diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs index dc3d27bf..1a484af8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs @@ -166,7 +166,7 @@ namespace UnityEngine.Rendering /// /// Opened state of the foldout. /// - public bool opened; + public bool opened { get; set; } /// /// Draw the foldout in full width using a header style. @@ -178,6 +178,11 @@ namespace UnityEngine.Rendering /// public List contextMenuItems = null; + /// + /// Optional help URL for the editor UI + /// + public string documentationUrl { get; set; } + private bool m_Dirty; private string[] m_ColumnLabels; private string[] m_ColumnTooltips; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs index 7c6c0495..9d5e3346 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs @@ -526,6 +526,64 @@ namespace UnityEngine.Rendering public Func> getObjects { get; set; } } + /// + /// A dropdown that contains a list of cameras + /// + public class CameraSelector : ObjectPopupField + { + /// + /// A dropdown that contains a list of cameras + /// + public CameraSelector() + { + displayName = "Camera"; + getObjects = () => cameras; + } + + private Camera[] m_CamerasArray; + private List m_Cameras = new List(); + + IEnumerable cameras + { + get + { + m_Cameras.Clear(); + +#if UNITY_EDITOR + if (UnityEditor.SceneView.lastActiveSceneView != null) + { + var sceneCamera = UnityEditor.SceneView.lastActiveSceneView.camera; + if (sceneCamera != null) + m_Cameras.Add(sceneCamera); + } +#endif + + if (m_CamerasArray == null || m_CamerasArray.Length != Camera.allCamerasCount) + { + m_CamerasArray = new Camera[Camera.allCamerasCount]; + } + + Camera.GetAllCameras(m_CamerasArray); + + foreach (var camera in m_CamerasArray) + { + if (camera == null) + continue; + + if (camera.cameraType != CameraType.Preview && camera.cameraType != CameraType.Reflection) + { + if (!camera.TryGetComponent(out var additionalData)) + Debug.LogWarning($"Camera {camera.name} does not contain an additional camera data component. Open the Game Object in the inspector to add additional camera data."); + else + m_Cameras.Add(camera); + } + } + + return m_Cameras; + } + } + } + /// /// Enumerator field with history. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Panel.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Panel.cs index fb77b880..688bf532 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Panel.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Panel.cs @@ -63,7 +63,7 @@ namespace UnityEngine.Rendering /// public Panel() { - children = new ObservableList(); + children = new ObservableList(0, (widget, widget1) => widget.order.CompareTo(widget1.order)); children.ItemAdded += OnItemAdded; children.ItemRemoved += OnItemRemoved; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs index ecd19161..33d08dd5 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs @@ -18,7 +18,7 @@ namespace UnityEngine.Rendering /// state (e.g., whether it is in the editor or playing at runtime). /// - `DebugUI` also includes helper methods for widget initialization, such as compact initialization using the `NameAndTooltip` struct. /// - /// This API lets you do the following: + /// This API lets you do the following: /// - Specify widget behavior such as "EditorOnly", "RuntimeOnly", "EditorForceUpdate", and "FrequentlyUsed". /// - Show dynamic data with optional formatting. /// - Specify delegate functions to show or hide widgets @@ -53,10 +53,10 @@ namespace UnityEngine.Rendering /// { /// // Set the display label /// displayName = "Current Time", - /// + /// /// // Set the format for the time /// getter = () => System.DateTime.Now.ToString("HH:mm:ss"), - /// + /// /// // Set the value to refresh every second /// refreshRate = 1f /// }; @@ -103,6 +103,11 @@ namespace UnityEngine.Rendering /// public abstract class Widget { + /// + /// The order of the widget + /// + public int order { get; set; } = 0; + // Set to null until it's added to a panel, be careful /// /// Panels containing the widget. diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs index daac1022..13712d37 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs @@ -10,5 +10,10 @@ namespace UnityEngine.Rendering /// /// The debug UI panel created. IDebugDisplaySettingsPanelDisposable CreatePanel(); + + /// + /// Resets the values of the settings data + /// + void Reset() { } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IVolumeDebugSettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IVolumeDebugSettings.cs index 249729ed..6f60a5bf 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IVolumeDebugSettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IVolumeDebugSettings.cs @@ -7,6 +7,7 @@ namespace UnityEngine.Rendering /// Volume debug settings. /// This variant is obsolete and kept only for not breaking user code. Use for all new usage. /// + [Obsolete("This is not longer supported Please use DebugDisplaySettingsVolume. #from(6000.2)", false)] public interface IVolumeDebugSettings { /// Selected component. @@ -65,7 +66,7 @@ namespace UnityEngine.Rendering /// Volume debug settings. /// #pragma warning disable CS0618 // Type or member is obsolete - [Obsolete("This variant is obsolete and kept only for not breaking user code. Use IVolumeDebugSettings instead. #from(23.2) (UnityUpgradable) -> IVolumeDebugSettings", false)] + [Obsolete("This is not longer supported Please use DebugDisplaySettingsVolume. #from(6000.2)", false)] public interface IVolumeDebugSettings2 : IVolumeDebugSettings #pragma warning restore CS0618 // Type or member is obsolete diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs index 155eb183..fb16e10b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs @@ -154,6 +154,18 @@ namespace UnityEngine.Rendering.UI Transform prefab; if (!m_PrefabsMap.TryGetValue(child.GetType(), out prefab)) + { + foreach (var pair in m_PrefabsMap) + { + if (pair.Key.IsAssignableFrom(child.GetType())) + { + prefab = pair.Value; + break; + } + } + } + + if (prefab == null) { Debug.LogWarning("DebugUI widget doesn't have a prefab: " + child.GetType()); continue; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerContainer.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerContainer.cs index 5b080933..1f8a2c13 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerContainer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerContainer.cs @@ -57,8 +57,7 @@ namespace UnityEngine.Rendering.UI if (!t.gameObject.activeInHierarchy) continue; - var c = t.GetComponent(); - if (c != null) + if (t.TryGetComponent(out var c)) list.Add(c); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObject.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObject.cs index f58514e3..06e68f35 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObject.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObject.cs @@ -16,8 +16,10 @@ namespace UnityEngine.Rendering.UI { base.SetWidget(widget); var field = CastWidget(); + nameLabel.text = field.displayName; - valueLabel.text = field.GetValue().name; + var obj = field.GetValue(); + valueLabel.text = obj != null ? obj.name : "None"; } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObjectPopupField.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObjectPopupField.cs index 649f6727..d884fd80 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObjectPopupField.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerObjectPopupField.cs @@ -29,7 +29,7 @@ namespace UnityEngine.Rendering.UI return; var elementsArray = elements.ToArray(); - var count = elementsArray.Count(); + var count = elementsArray.Length; if (m_Index >= count) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerRow.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerRow.cs index 9c19dc1a..72afa202 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerRow.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerRow.cs @@ -42,7 +42,7 @@ namespace UnityEngine.Rendering.UI bool IsActive(DebugUI.Table table, int index, GameObject child) { - if (!table.GetColumnVisibility(index)) + if (table == null || !table.GetColumnVisibility(index)) return false; var valueChild = child.transform.Find("Value"); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerWidget.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerWidget.cs index 3b34da02..567cbecb 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerWidget.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerWidget.cs @@ -109,13 +109,7 @@ namespace UnityEngine.Rendering.UI /// Previous widget UI handler, parent if there is none. public virtual DebugUIHandlerWidget Previous() { - if (previousUIHandler != null) - return previousUIHandler; - - if (parentUIHandler != null) - return parentUIHandler; - - return null; + return previousUIHandler != null ? previousUIHandler : parentUIHandler; } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/VolumeDebugSettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/VolumeDebugSettings.cs index d2310ebd..8f290097 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/VolumeDebugSettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/VolumeDebugSettings.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using Unity.Mathematics; using UnityEditor; namespace UnityEngine.Rendering @@ -11,6 +10,7 @@ namespace UnityEngine.Rendering /// The volume settings /// /// A with + [Obsolete("This is not longer supported Please use DebugDisplaySettingsVolume. #from(6000.2)", false)] public abstract partial class VolumeDebugSettings : IVolumeDebugSettings where T : MonoBehaviour, IAdditionalData { @@ -152,7 +152,7 @@ namespace UnityEngine.Rendering float weight = Mathf.Clamp01(volume.weight); if (!volume.isGlobal) { - var colliders = volume.GetComponents(); + var colliders = volume.colliders; // Find closest distance to volume, 0 means it's inside it float closestDistanceSqr = float.PositiveInfinity; @@ -191,7 +191,7 @@ namespace UnityEngine.Rendering VolumeParameter[,] GetStates() { var fields = selectedComponentType - .GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(t => t.FieldType.IsSubclassOf(typeof(VolumeParameter))) .ToArray(); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Documentation.cs b/Packages/com.unity.render-pipelines.core/Runtime/Documentation.cs index 242fbc31..e5a03f27 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Documentation.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Documentation.cs @@ -79,7 +79,7 @@ namespace UnityEngine.Rendering get { #if UNITY_EDITOR - if (DocumentationUtils.TryGetPackageInfoForType(GraphicsSettings.currentRenderPipeline?.GetType() ?? typeof(DocumentationInfo), out var package, out var version)) + if (DocumentationUtils.TryGetPackageInfoForType(GraphicsSettings.currentRenderPipelineAssetType ?? typeof(DocumentationInfo), out var package, out var version)) { return DocumentationInfo.GetPackageLink(package, version, pageName, pageHash); } @@ -88,6 +88,73 @@ namespace UnityEngine.Rendering } } } + + /// + /// Use this attribute to define a documentation URL that is only active when a specific Render Pipeline is in use. + /// + /// + /// + /// [PipelineHelpURL("HDRenderPipelineAsset", "hdrp-page-name")] + /// [PipelineHelpURL("UniversalRenderPipelineAsset", "urp-page-name")] + /// public class MyHDRPComponent : MonoBehaviour { /* ... */ } + /// + /// + /// + /// The URL will only be generated if the active Scriptable Render Pipeline Asset's type name exactly matches the pipelineName provided. + /// + /// + [Conditional("UNITY_EDITOR")] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = true)] + public class PipelineHelpURLAttribute : HelpURLAttribute + { + private string pipelineName { get; } + + private string pageName { get; } + + private string pageHash { get; } + + /// + /// Initializes the attribute to link to a specific documentation page for a named Render Pipeline. + /// + /// The exact Type name of the Render Pipeline Asset (e.g., "UniversalRenderPipelineAsset", "HDRenderPipelineAsset") for which this URL is valid. + /// The name of the documentation page. + /// Optional. The specific section anchor (#) on the documentation page. + public PipelineHelpURLAttribute(string pipelineName, string pageName, string pageHash = "") + : base(null) + { + this.pipelineName = pipelineName; + this.pageName = pageName; + this.pageHash = pageHash; + } + + /// + /// Returns the URL to the specified page within the documentation for the designated Render Pipeline, + /// but only if that pipeline is currently active. + /// + /// + /// Checks if a Scriptable Render Pipeline is enabled and if its asset type name matches the pipelineName + /// provided in the constructor. If conditions are met and package info is found, constructs the URL. + /// Otherwise, returns an empty string. + /// + public override string URL + { + get + { +#if UNITY_EDITOR + if (string.IsNullOrEmpty(pipelineName) || !GraphicsSettings.isScriptableRenderPipelineEnabled) + return string.Empty; + + var pipelineType = GraphicsSettings.currentRenderPipelineAssetType; + if (pipelineType.Name != pipelineName) + return string.Empty; + + if (DocumentationUtils.TryGetPackageInfoForType(pipelineType, out var package, out var version)) + return DocumentationInfo.GetPackageLink(package, version, pageName, pageHash); +#endif + return string.Empty; + } + } + } //We need to have only one version number amongst packages (so public) /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/AssemblyInfo.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/AssemblyInfo.cs index 306bf1bd..3441704c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/AssemblyInfo.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/AssemblyInfo.cs @@ -2,3 +2,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor")] [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Tests")] +[assembly: InternalsVisibleTo("UnityEngine.TestTools.Graphics.Contexts")] 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 773befe1..291da156 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,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using Unity.Collections; #if UNITY_EDITOR using UnityEditor; @@ -12,6 +13,7 @@ namespace UnityEngine.Rendering /// /// GPU Resident Drawer Rendering Debugger settings. /// + [CurrentPipelineHelpURL("gpu-resident-drawer")] public class DebugDisplayGPUResidentDrawer : IDebugDisplaySettingsData { const string k_FormatString = "{0}"; @@ -275,17 +277,20 @@ namespace UnityEngine.Rendering }; } - - [DisplayInfo(name = "GPU Resident Drawer", order = 5)] - [CurrentPipelineHelpURL("gpu-resident-drawer")] + [DisplayInfo(name = "Rendering", order = 5)] private class SettingsPanel : DebugDisplaySettingsPanel { - public override string PanelName => "GPU Resident Drawer"; - public override DebugUI.Flags Flags => DebugUI.Flags.EditorForceUpdate; public SettingsPanel(DebugDisplayGPUResidentDrawer data) { + var foldout = new DebugUI.Foldout() + { + displayName = Strings.drawerSettingsContainerName, + documentationUrl = typeof(DebugDisplayGPUResidentDrawer).GetCustomAttribute()?.URL + }; + AddWidget(foldout); + var helpBox = new DebugUI.MessageBox() { displayName = "Not Supported", @@ -297,10 +302,9 @@ namespace UnityEngine.Rendering }, isHiddenCallback = () => GPUResidentDrawer.IsEnabled() }; + foldout.children.Add(helpBox); - AddWidget(helpBox); - - AddWidget(new Container() + foldout.children.Add(new Container() { displayName = Strings.occlusionCullingTitle, isHiddenCallback = () => !GPUResidentDrawer.IsEnabled(), @@ -318,14 +322,12 @@ namespace UnityEngine.Rendering }); AddOcclusionContextStatsWidget(data); - AddWidget(new DebugUI.Container() + foldout.children.Add(new DebugUI.BoolField { - displayName = Strings.drawerSettingsContainerName, - isHiddenCallback = () => !GPUResidentDrawer.IsEnabled(), - children = - { - new DebugUI.BoolField { nameAndTooltip = Strings.displayBatcherStats, getter = () => data.displayBatcherStats, setter = value => data.displayBatcherStats = value}, - } + nameAndTooltip = Strings.displayBatcherStats, + getter = () => data.displayBatcherStats, + setter = value => data.displayBatcherStats = value, + isHiddenCallback = () => !GPUResidentDrawer.IsEnabled() }); AddInstanceCullingStatsWidget(data); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.Validator.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.Validator.cs index f76c930b..bf5d886f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.Validator.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.Validator.cs @@ -88,7 +88,7 @@ namespace UnityEngine.Rendering return false; #endif // If we are forcing the system, no need to perform further checks - if (IsForcedOnViaCommandLine()) + if (IsForcedOnViaCommandLine() || MaintainContext) return true; if (GraphicsSettings.currentRenderPipeline is not IGPUResidentRenderPipeline asset) 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 b5fdf4ec..32fc033a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs @@ -113,7 +113,7 @@ namespace UnityEngine.Rendering public static void ReinitializeIfNeeded() { #if UNITY_EDITOR - if (!IsForcedOnViaCommandLine() && (IsProjectSupported() != IsEnabled())) + if (!IsForcedOnViaCommandLine() && !MaintainContext && (IsProjectSupported() != IsEnabled())) { Reinitialize(); } @@ -237,7 +237,7 @@ namespace UnityEngine.Rendering if (IsForcedOnViaCommandLine()) settings.mode = GPUResidentDrawerMode.InstancedDrawing; - if (IsOcclusionForcedOnViaCommandLine()) + if (IsOcclusionForcedOnViaCommandLine() || ForceOcclusion) settings.enableOcclusionCulling = true; return settings; @@ -247,7 +247,7 @@ namespace UnityEngine.Rendering /// Is GRD forced on via the command line via -force-gpuresidentdrawer. Editor only. /// /// true if forced on - private static bool IsForcedOnViaCommandLine() + internal static bool IsForcedOnViaCommandLine() { #if UNITY_EDITOR return s_IsForcedOnViaCommandLine; @@ -260,7 +260,7 @@ namespace UnityEngine.Rendering /// Is occlusion culling forced on via the command line via -force-gpuocclusion. Editor only. /// /// true if forced on - private static bool IsOcclusionForcedOnViaCommandLine() + internal static bool IsOcclusionForcedOnViaCommandLine() { #if UNITY_EDITOR return s_IsOcclusionForcedOnViaCommandLine; @@ -269,6 +269,9 @@ namespace UnityEngine.Rendering #endif } + internal static bool MaintainContext { get; set; } = false; + internal static bool ForceOcclusion { get; set; } = false; + internal static void Reinitialize() { var settings = GetGlobalSettingsFromRPAsset(); @@ -392,9 +395,11 @@ namespace UnityEngine.Rendering m_Dispatcher.EnableTypeTracking(TypeTrackingFlags.SceneObjects); m_Dispatcher.EnableTypeTracking(); m_Dispatcher.EnableTypeTracking(); - m_Dispatcher.EnableTransformTracking(TransformTrackingType.GlobalTRS); m_Dispatcher.EnableTypeTracking(TypeTrackingFlags.SceneObjects); + m_Dispatcher.EnableTypeTracking(TypeTrackingFlags.SceneObjects | TypeTrackingFlags.EditorOnlyObjects); + m_Dispatcher.EnableTransformTracking(TransformTrackingType.GlobalTRS); + m_Dispatcher.EnableTransformTracking(TransformTrackingType.GlobalTRS); #if UNITY_EDITOR AssemblyReloadEvents.beforeAssemblyReload += OnAssemblyReload; @@ -567,6 +572,7 @@ namespace UnityEngine.Rendering var lodGroupTransformData = m_Dispatcher.GetTransformChangesAndClear(TransformTrackingType.GlobalTRS, Allocator.TempJob); var lodGroupData = m_Dispatcher.GetTypeChangesAndClear(Allocator.TempJob, noScriptingArray: true); var meshDataSorted = m_Dispatcher.GetTypeChangesAndClear(Allocator.TempJob, sortByInstanceID: true, noScriptingArray: true); + var cameraChanges = m_Dispatcher.GetTypeChangesAndClear(Allocator.TempJob, noScriptingArray: true); var materialData = m_Dispatcher.GetTypeChangesAndClear(Allocator.TempJob, noScriptingArray: true); var rendererData = m_Dispatcher.GetTypeChangesAndClear(Allocator.TempJob, noScriptingArray: true); Profiler.EndSample(); @@ -593,6 +599,10 @@ namespace UnityEngine.Rendering ProcessLODGroups(lodGroupData.changedID, lodGroupData.destroyedID, lodGroupTransformData.transformedID); Profiler.EndSample(); + Profiler.BeginSample("GPUResidentDrawer.ProcessCameras"); + ProcessCameras(cameraChanges.changedID, cameraChanges.destroyedID); + Profiler.EndSample(); + Profiler.BeginSample("GPUResidentDrawer.ProcessRenderers"); ProcessRenderers(rendererData, unsupportedRenderers.AsArray()); Profiler.EndSample(); @@ -605,6 +615,7 @@ namespace UnityEngine.Rendering lodGroupData.Dispose(); meshDataSorted.Dispose(); materialData.Dispose(); + cameraChanges.Dispose(); rendererData.Dispose(); unsupportedChangedMaterials.Dispose(); unsupportedRenderers.Dispose(); @@ -634,6 +645,12 @@ namespace UnityEngine.Rendering m_Batcher.DestroyMaterials(unsupportedMaterials); } + private void ProcessCameras(NativeArray changedIDs, NativeArray destroyedIDs) + { + m_BatchersContext.UpdateCameras(changedIDs); + m_BatchersContext.FreePerCameraInstanceData(destroyedIDs); + } + private void ProcessMeshes(NativeArray destroyedID) { if (destroyedID.Length == 0) @@ -686,7 +703,7 @@ namespace UnityEngine.Rendering Profiler.BeginSample("GPUResidentDrawer.FindRenderersFromMaterialsOrMeshes"); - var (renderersWithChangedMaterials, renderersWithChangedMeshes) = FindRenderersFromMaterialsOrMeshes(sortedExcludedRenderers, filteredMaterials, changedMeshes, Allocator.TempJob); + var (renderersWithChangedMaterials, renderersWithChangeMeshes) = FindRenderersFromMaterialsOrMeshes(sortedExcludedRenderers, filteredMaterials, changedMeshes, Allocator.TempJob); filteredMaterials.Dispose(); Profiler.EndSample(); @@ -694,35 +711,33 @@ namespace UnityEngine.Rendering sortedExcludedRenderers.Dispose(); updatePackedMaterialCacheJob.Complete(); - if (renderersWithChangedMaterials.Length == 0 && renderersWithChangedMeshes.Length == 0) + if (renderersWithChangedMaterials.Length == 0 && renderersWithChangeMeshes.Length == 0) { renderersWithChangedMaterials.Dispose(); - renderersWithChangedMeshes.Dispose(); + renderersWithChangeMeshes.Dispose(); return; } Profiler.BeginSample("GPUResidentDrawer.UpdateRenderers"); { var changedMaterialsCount = renderersWithChangedMaterials.Length; - var changedMeshesCount = renderersWithChangedMeshes.Length; + var changedMeshesCount = renderersWithChangeMeshes.Length; var totalCount = changedMaterialsCount + changedMeshesCount; var changedInstances = new NativeArray(totalCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var changedRenderers = new NativeArray(totalCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); NativeArray.Copy(renderersWithChangedMaterials.AsArray(), changedRenderers, changedMaterialsCount); - NativeArray.Copy(renderersWithChangedMeshes.AsArray(), changedRenderers.GetSubArray(changedMaterialsCount, changedMeshesCount), changedMeshesCount); + NativeArray.Copy(renderersWithChangeMeshes.AsArray(), changedRenderers.GetSubArray(changedMaterialsCount, changedMeshesCount), changedMeshesCount); ScheduleQueryRendererGroupInstancesJob(changedRenderers, changedInstances).Complete(); m_Batcher.DestroyDrawInstances(changedInstances); m_Batcher.UpdateRenderers(renderersWithChangedMaterials.AsArray(), true); - m_Batcher.UpdateRenderers(renderersWithChangedMeshes.AsArray(), false); + m_Batcher.UpdateRenderers(renderersWithChangeMeshes.AsArray(), false); - changedInstances.Dispose(); - changedRenderers.Dispose(); renderersWithChangedMaterials.Dispose(); - renderersWithChangedMeshes.Dispose(); + renderersWithChangeMeshes.Dispose(); } Profiler.EndSample(); } 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 1c206649..ce248771 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCuller.cs @@ -66,6 +66,7 @@ namespace UnityEngine.Rendering { public BatchMeshID meshID; public int submeshIndex; + public int activeMeshLod; // or -1 if this draw is not using mesh LOD public BatchMaterialID materialID; public BatchDrawCommandFlags flags; public int transparentInstanceId; // non-zero for transparent instances, to ensure each instance has its own draw command (for sorting) @@ -78,6 +79,7 @@ namespace UnityEngine.Rendering return meshID == other.meshID && submeshIndex == other.submeshIndex && + activeMeshLod == other.activeMeshLod && materialID == other.materialID && flags == other.flags && transparentInstanceId == other.transparentInstanceId && @@ -91,6 +93,7 @@ namespace UnityEngine.Rendering int hash = 13; hash = (hash * 23) + (int)meshID.value; hash = (hash * 23) + (int)submeshIndex; + hash = (hash * 23) + (int)activeMeshLod; hash = (hash * 23) + (int)materialID.value; hash = (hash * 23) + (int)flags; hash = (hash * 23) + transparentInstanceId; @@ -133,15 +136,53 @@ namespace UnityEngine.Rendering } [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] + internal struct AnimateCrossFadeJob : IJobParallelFor + { + public const int k_BatchSize = 512; + public const byte k_MeshLODTransitionToLowerLODBit = 0x80; + + private const byte k_LODFadeOff = (byte)CullingJob.k_LODFadeOff; + private const float k_CrossfadeAnimationTimeS = 0.333f; + + [ReadOnly] public float deltaTime; + + public UnsafeList crossFadeArray; + + public unsafe void Execute(int instanceIndex) + { + ref var crossFadeValue = ref crossFadeArray.ElementAt(instanceIndex); + + if(crossFadeValue == k_LODFadeOff) + return; + + var prevTransitionBit = (crossFadeValue & k_MeshLODTransitionToLowerLODBit); + + crossFadeValue += (byte)((deltaTime / k_CrossfadeAnimationTimeS) * 127.0f); + + //If done with crossfade - reset mask + if (prevTransitionBit != ((crossFadeValue + 1) & k_MeshLODTransitionToLowerLODBit)) + { + crossFadeValue = k_LODFadeOff; + } + } + } + + [BurstCompile] internal struct CullingJob : IJobParallelFor { public const int k_BatchSize = 32; - const uint k_LODFadeZeroPacked = 127; + public const uint k_MeshLodCrossfadeActive = 0x40; + public const uint k_MeshLodCrossfadeSignBit = 0x80; + public const uint k_MeshLodCrossfadeBits = k_MeshLodCrossfadeSignBit | k_MeshLodCrossfadeActive; - const float k_LODPercentInvisible = 0.0f; - const float k_LODPercentFullyVisible = 1.0f; - const float k_LODPercentSpeedTree = 2.0f; + public const uint k_LODFadeOff = 255u; + public const uint k_LODFadeZeroPacked = 127u; + public const uint k_LODFadeIsSpeedTree = 256u; + + private const uint k_InvalidCrossFadeAndLevel = 0xFFFFFFFF; + + const uint k_VisibilityMaskNotVisible = 0u; const float k_SmallMeshTransitionWidth = 0.1f; @@ -149,7 +190,7 @@ namespace UnityEngine.Rendering { kDisabled, kCrossFadeOut, // 1 == instance is visible in current lod, and not next - could be fading out - kCrossFadeIn, // 2 == instance is visivle in next lod level, but not current - could be fading in + kCrossFadeIn, // 2 == instance is visible in next lod level, but not current - could be fading in kVisible // 3 == instance is visible in both current and next lod level - could not be impacted by fade } @@ -157,6 +198,7 @@ namespace UnityEngine.Rendering [ReadOnly] public BatchCullingViewType viewType; [ReadOnly] public float3 cameraPosition; + [ReadOnly] public float sqrMeshLodSelectionConstant; [ReadOnly] public float sqrScreenRelativeMetric; [ReadOnly] public float minScreenRelativeHeight; [ReadOnly] public bool isOrtho; @@ -164,6 +206,7 @@ namespace UnityEngine.Rendering [ReadOnly] public int maxLOD; [ReadOnly] public uint cullingLayerMask; [ReadOnly] public ulong sceneCullingMask; + [ReadOnly] public bool animateCrossFades; [ReadOnly] public NativeArray frustumPlanePackets; [ReadOnly] public NativeArray frustumSplitInfos; @@ -176,7 +219,10 @@ namespace UnityEngine.Rendering [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeList lodGroupCullingData; [NativeDisableUnsafePtrRestriction] [ReadOnly] public IntPtr occlusionBuffer; + [NativeDisableContainerSafetyRestriction] public CPUPerCameraInstanceData.PerCameraInstanceDataArrays cameraInstanceData; + [NativeDisableParallelForRestriction][WriteOnly] public NativeArray rendererVisibilityMasks; + [NativeDisableParallelForRestriction][WriteOnly] public NativeArray rendererMeshLodSettings; [NativeDisableParallelForRestriction][WriteOnly] public NativeArray rendererCrossFadeValues; @@ -192,124 +238,127 @@ namespace UnityEngine.Rendering return packed; } - unsafe float CalculateLODVisibility(int instanceIndex, int sharedInstanceIndex, InstanceFlags instanceFlags) + unsafe uint CalculateLODVisibility(int instanceIndex, int sharedInstanceIndex, InstanceFlags instanceFlags) { - var lodPercent = k_LODPercentFullyVisible; var lodDataIndexAndMask = sharedInstanceData.lodGroupAndMasks[sharedInstanceIndex]; - if (lodDataIndexAndMask != 0xFFFFFFFF) + if (lodDataIndexAndMask == k_InvalidCrossFadeAndLevel) { - lodPercent = k_LODPercentInvisible; + if(viewType >= BatchCullingViewType.SelectionOutline + || (instanceFlags & InstanceFlags.SmallMeshCulling) == 0 + || minScreenRelativeHeight == 0.0f) + return k_LODFadeOff; - var lodIndex = lodDataIndexAndMask >> 8; - var lodMask = lodDataIndexAndMask & 0xFF; - Assert.IsTrue(lodMask > 0); - - ref var lodGroup = ref lodGroupCullingData.ElementAt((int)lodIndex); - if (lodGroup.forceLODMask != 0) - return (lodGroup.forceLODMask & lodMask) != 0 ? k_LODPercentFullyVisible : k_LODPercentInvisible; - - float cameraSqrDistToLODCenter = isOrtho ? sqrScreenRelativeMetric : LODGroupRenderingUtils.CalculateSqrPerspectiveDistance(lodGroup.worldSpaceReferencePoint, cameraPosition, sqrScreenRelativeMetric); + // If no LODGroup available - small mesh culling. + ref readonly AABB worldAABB = ref instanceData.worldAABBs.UnsafeElementAt(instanceIndex); + var cameraSqrDist = isOrtho ? sqrScreenRelativeMetric : LODRenderingUtils.CalculateSqrPerspectiveDistance(worldAABB.center, cameraPosition, sqrScreenRelativeMetric); + var cameraDist = math.sqrt(cameraSqrDist); - // Remove lods that are beyond the max lod. - uint maxLodMask = 0xffffffff << maxLOD; - lodMask &= maxLodMask; + var aabbSize = worldAABB.extents * 2.0f; + var worldSpaceSize = math.max(math.max(aabbSize.x, aabbSize.y), aabbSize.z); + var maxDist = LODRenderingUtils.CalculateLODDistance(minScreenRelativeHeight, worldSpaceSize); + if (maxDist < cameraDist) + return k_LODFadeZeroPacked; - // Offset to the lod preceding the first for proper cross fade calculation. - int m = math.max(math.tzcnt(lodMask) - 1, maxLOD); - lodMask >>= m; + var transitionHeight = minScreenRelativeHeight + k_SmallMeshTransitionWidth * minScreenRelativeHeight; + var fadeOutRange = Mathf.Max(0.0f,maxDist - LODRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize)); - while (lodMask > 0) - { - var lodRangeSqrMin = m == maxLOD ? 0.0f : lodGroup.sqrDistances[m - 1]; - var lodRangeSqrMax = lodGroup.sqrDistances[m]; + var lodPercent = (maxDist - cameraDist) / fadeOutRange; + return lodPercent > 1.0f ? k_LODFadeOff : PackFloatToUint8(lodPercent); + } - // Camera is beyond the range of this all further lods. No need to proceed. - if (cameraSqrDistToLODCenter < lodRangeSqrMin) - break; + var lodIndex = lodDataIndexAndMask >> 8; + var lodMask = lodDataIndexAndMask & 0xFF; + Assert.IsTrue(lodMask > 0); - // Instance is in the min/max range of this lod. Proceeding. - if (cameraSqrDistToLODCenter < lodRangeSqrMax) - { - var type = (CrossFadeType)(lodMask & 3); + ref var lodGroup = ref lodGroupCullingData.ElementAt((int)lodIndex); - // Instance is in this and/or the next lod. - if (type != CrossFadeType.kDisabled) - { - // Instance is in both this and the next lod. No need to fade. - if (type == CrossFadeType.kVisible) - { - lodPercent = k_LODPercentFullyVisible; - } - else - { - var distanceToLodCenter = math.sqrt(cameraSqrDistToLODCenter); - var maxDist = math.sqrt(lodRangeSqrMax); + if (lodGroup.forceLODMask != 0) + return (lodGroup.forceLODMask & lodMask) != 0 ? k_LODFadeOff : k_LODFadeZeroPacked; - // SpeedTree cross fade. - if (lodGroup.percentageFlags[m]) - { - // The fading-in instance is not visible but the fading-out is visible and it does the speed tree vertex deformation. + float cameraSqrDistToLODCenter = isOrtho ? sqrScreenRelativeMetric : LODRenderingUtils.CalculateSqrPerspectiveDistance(lodGroup.worldSpaceReferencePoint, cameraPosition, sqrScreenRelativeMetric); - if (type == CrossFadeType.kCrossFadeIn) - { - lodPercent = k_LODPercentInvisible; - } - else if (type == CrossFadeType.kCrossFadeOut) - { - var minDist = m > 0 ? math.sqrt(lodGroup.sqrDistances[m - 1]) : lodGroup.worldSpaceSize; - lodPercent = k_LODPercentSpeedTree + math.max(distanceToLodCenter - minDist, 0.0f) / (maxDist - minDist); - } - } - // Dithering cross fade. - else - { - // If in the transition zone, both fading-in and fading-out instances are visible. Calculate the lod percent. - // If not then only the fading-out instance is fully visible, and fading-in is invisible. + // Remove lods that are beyond the max lod. + uint maxLodMask = 0xffffffff << maxLOD; + lodMask &= maxLodMask; - var transitionDist = lodGroup.transitionDistances[m]; - var dif = maxDist - distanceToLodCenter; + // Offset to the lod preceding the first for proper cross fade calculation. + int m = math.max(math.tzcnt(lodMask) - 1, maxLOD); + lodMask >>= m; - if (dif < transitionDist) - { - lodPercent = dif / transitionDist; + while (lodMask > 0) + { + var lodRangeSqrMin = m == maxLOD ? 0.0f : lodGroup.sqrDistances[m - 1]; + var lodRangeSqrMax = lodGroup.sqrDistances[m]; - if (type == CrossFadeType.kCrossFadeIn) - lodPercent = -lodPercent; - } - else if (type == CrossFadeType.kCrossFadeOut) - { - lodPercent = k_LODPercentFullyVisible; - } - } - } - } + // Camera is beyond the range of this all further lods. No need to proceed. + if (cameraSqrDistToLODCenter < lodRangeSqrMin) + break; - // We found the lod and the percentage. - break; - } + if (cameraSqrDistToLODCenter > lodRangeSqrMax) + { ++m; lodMask >>= 1; + continue; } - } - else if(viewType < BatchCullingViewType.SelectionOutline && (instanceFlags & InstanceFlags.SmallMeshCulling) != 0) - { - ref readonly AABB worldAABB = ref instanceData.worldAABBs.UnsafeElementAt(instanceIndex); - var cameraSqrDist = isOrtho ? sqrScreenRelativeMetric : LODGroupRenderingUtils.CalculateSqrPerspectiveDistance(worldAABB.center, cameraPosition, sqrScreenRelativeMetric); - var cameraDist = math.sqrt(cameraSqrDist); - var aabbSize = worldAABB.extents * 2.0f; - var worldSpaceSize = math.max(math.max(aabbSize.x, aabbSize.y), aabbSize.z); - var maxDist = LODGroupRenderingUtils.CalculateLODDistance(minScreenRelativeHeight, worldSpaceSize); + // Instance is in the min/max range of this lod. Proceeding. + var type = (CrossFadeType)(lodMask & 3); - var transitionHeight = minScreenRelativeHeight + k_SmallMeshTransitionWidth * minScreenRelativeHeight; - var fadeOutRange = Mathf.Max(0.0f,maxDist - LODGroupRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize)); + // Instance is in neither this LOD Level nor next - invisible + if (type == CrossFadeType.kDisabled) + { + return k_LODFadeZeroPacked; + } + // Instance is in both this and the next lod. No need to fade - fully visible + if (type == CrossFadeType.kVisible) + { + return k_LODFadeOff; + } + + var distanceToLodCenter = math.sqrt(cameraSqrDistToLODCenter); + var maxDist = math.sqrt(lodRangeSqrMax); + + // SpeedTree cross fade. + if (lodGroup.percentageFlags[m]) + { + // The fading-in instance is not visible but the fading-out is visible and it does the speed tree vertex deformation. + if (type == CrossFadeType.kCrossFadeIn) + { + return k_LODFadeZeroPacked + 1; + } + else if (type == CrossFadeType.kCrossFadeOut) + { + var minDist = m > 0 + ? math.sqrt(lodGroup.sqrDistances[m - 1]) + : lodGroup.worldSpaceSize; + var lodPercent = math.max(distanceToLodCenter - minDist, 0.0f) / (maxDist - minDist); + return PackFloatToUint8(lodPercent) | k_LODFadeIsSpeedTree; + } + } + // Dithering cross fade. + else + { + var transitionDist = lodGroup.transitionDistances[m]; + var dif = maxDist - distanceToLodCenter; + // If in the transition zone, both fading-in and fading-out instances are visible. Calculate the lod percent. + // If not then only the fading-out instance is fully visible, and fading-in is invisible. + if (dif < transitionDist) + { + var lodPercent = dif / transitionDist; + + if (type == CrossFadeType.kCrossFadeIn) + lodPercent = -lodPercent; + return PackFloatToUint8(lodPercent); + } + + return type == CrossFadeType.kCrossFadeOut ? k_LODFadeOff : k_LODFadeZeroPacked; + } - lodPercent = math.saturate((maxDist - cameraDist) / fadeOutRange); } - return lodPercent; + return k_LODFadeZeroPacked; } private unsafe uint CalculateVisibilityMask(int instanceIndex, int sharedInstanceIndex, InstanceFlags instanceFlags) @@ -350,6 +399,87 @@ namespace UnityEngine.Rendering return visibilityMask; } + // Algorithm is detailed and must be kept in sync with CalculateMeshLod (C++) + private uint ComputeMeshLODLevel(int instanceIndex, int sharedInstanceIndex) + { + ref readonly GPUDrivenRendererMeshLodData meshLodData = ref instanceData.meshLodData.UnsafeElementAt(instanceIndex); + + if (meshLodData.forceLod >= 0) + return (uint)meshLodData.forceLod; + + var levelInfo = sharedInstanceData.meshLodInfos[sharedInstanceIndex]; + ref readonly AABB worldAABB = ref instanceData.worldAABBs.UnsafeElementAt(instanceIndex); + + var radiusSqr = math.max(math.lengthsq(worldAABB.extents), 1e-5f); + var diameterSqr = radiusSqr * 4; + var cameraSqrHeightAtDistance = isOrtho ? sqrMeshLodSelectionConstant : + LODRenderingUtils.CalculateSqrPerspectiveDistance(worldAABB.center, cameraPosition, sqrMeshLodSelectionConstant); + + var boundsDesiredPercentage = Math.Sqrt(cameraSqrHeightAtDistance / diameterSqr); + + var levelIndexFlt = math.log2(boundsDesiredPercentage) * levelInfo.lodSlope + levelInfo.lodBias; + + // We apply Bias after max to enforce that a positive bias of +N we would select lodN instead of Lod0 + levelIndexFlt = math.max(levelIndexFlt, 0); + levelIndexFlt += meshLodData.lodSelectionBias; + + levelIndexFlt = math.clamp(levelIndexFlt,0, levelInfo.levelCount - 1); + + return (uint)math.floor(levelIndexFlt); + } + + // A crossfading instance is assigned a [0.0(invisible) - 1.0(fully visible)] value. + // The complementary instance is assigned the negative of this value[-1.0(invisible) - -0.0(fully visible)] + // As we pack it to a 8-bit uint, we transition from [0-126] when transitioning from a Lower to a higher LOD level, + // and from [127-254] when transitioning from a higher to a lower LOD level. + // This means that we can use (k_MeshLODTransitionToLowerLODBit = 0x80) to select the correct instance to blend with during draw command generation. + private unsafe uint ComputeMeshLODCrossfade(int instanceIndex, ref uint meshLodLevel) + { + var previousLodLevel = cameraInstanceData.meshLods[instanceIndex]; + + //1st frame - previous LOD level is invalid. Just update it and return. + if(previousLodLevel == 0xff) + { + cameraInstanceData.meshLods[instanceIndex] = (byte)meshLodLevel; + return k_LODFadeOff; + } + + var currentCrossFade = cameraInstanceData.crossFades[instanceIndex]; + + // If not already crossfading, check if we changed Lod level this frame, and starts crossfading. + if (currentCrossFade == k_LODFadeOff) + { + if (previousLodLevel == meshLodLevel) + return k_LODFadeOff; + + cameraInstanceData.meshLods[instanceIndex] = (byte)meshLodLevel; + cameraInstanceData.crossFades[instanceIndex] = (byte)(meshLodLevel < previousLodLevel ? AnimateCrossFadeJob.k_MeshLODTransitionToLowerLODBit : 1); + meshLodLevel = previousLodLevel; + return k_LODFadeOff; + } + + //On the first crossfading frame, other cameras could have set the current crossfade values, but we do not want to fade until next frame. + if ((currentCrossFade - 1) % k_LODFadeZeroPacked == 0) + { + meshLodLevel = previousLodLevel; + return k_LODFadeOff; + } + + meshLodLevel = previousLodLevel | (currentCrossFade > k_LODFadeZeroPacked ? k_MeshLodCrossfadeBits : k_MeshLodCrossfadeActive); + + return currentCrossFade; + } + + private unsafe void EnforcePreviousFrameMeshLOD(int instanceIndex, ref uint meshLodLevel) + { + ref var previousLodLevel = ref cameraInstanceData.meshLods.ElementAt(instanceIndex); + + if (previousLodLevel != k_LODFadeOff) + { + meshLodLevel = previousLodLevel; + } + } + public void Execute(int instanceIndex) { InstanceHandle instance = instanceData.instances[instanceIndex]; @@ -357,48 +487,55 @@ namespace UnityEngine.Rendering var instanceFlags = sharedInstanceData.flags[sharedInstanceIndex].instanceFlags; var visibilityMask = CalculateVisibilityMask(instanceIndex, sharedInstanceIndex, instanceFlags); - var crossFadeValue = k_LODFadeZeroPacked; + if (visibilityMask == k_VisibilityMaskNotVisible) + { + rendererVisibilityMasks[instance.index] = (byte)k_VisibilityMaskNotVisible; + return; + } + + var crossFadeValue = CalculateLODVisibility(instanceIndex, sharedInstanceIndex, instanceFlags); + if (crossFadeValue == k_LODFadeZeroPacked) + { + rendererVisibilityMasks[instance.index] = (byte)k_VisibilityMaskNotVisible; + return; + } + + if (binningConfig.supportsMotionCheck) + { + bool hasMotion = instanceData.movedInPreviousFrameBits.Get(instanceIndex); + visibilityMask = (visibilityMask << 1) | (hasMotion ? 1U : 0); + } - if (visibilityMask != 0) + var meshLodLevel = 0u; + // select mesh LOD level + var hasMeshLod = (instanceFlags & InstanceFlags.HasMeshLod) != 0; + if (hasMeshLod) { - float lodPercent = CalculateLODVisibility(instanceIndex, sharedInstanceIndex, instanceFlags); + meshLodLevel = ComputeMeshLODLevel(instanceIndex, sharedInstanceIndex); + } - if (lodPercent != k_LODPercentInvisible) + if (binningConfig.supportsCrossFade) + { + if(hasMeshLod && animateCrossFades) { - if (binningConfig.supportsMotionCheck) + //Only Crossfade mesh LOD if we aren't already crossfading through LOD groups or SpeedTree + if (crossFadeValue == k_LODFadeOff) { - bool hasMotion = instanceData.movedInPreviousFrameBits.Get(instanceIndex); - visibilityMask = (visibilityMask << 1) | (hasMotion ? 1U : 0); + crossFadeValue = ComputeMeshLODCrossfade(instanceIndex, ref meshLodLevel); } - - if (binningConfig.supportsCrossFade) + else { - bool hasDitheringCrossFade = false; - - if (lodPercent != k_LODPercentFullyVisible) - { - bool isSpeedTreeCrossFade = lodPercent >= k_LODPercentSpeedTree; - - // If this is a speed tree cross fade then we provide cross fade value but we don't enable cross fade keyword. - if (isSpeedTreeCrossFade) - lodPercent -= k_LODPercentSpeedTree; - else - hasDitheringCrossFade = true; - - crossFadeValue = PackFloatToUint8(lodPercent); - } - - visibilityMask = (visibilityMask << 1) | (hasDitheringCrossFade ? 1U : 0); + // If we are cross fading through LODGroup, we reuse previous frame's LodLevel to avoid popping + EnforcePreviousFrameMeshLOD(instanceIndex, ref meshLodLevel); } } - else - { - visibilityMask = 0; - } + // if crossfade is 255 or more, either crossfade is off or it's speedTreeFade, cases for which we do not need to set the fade bit. + visibilityMask = (visibilityMask << 1) | (crossFadeValue < k_LODFadeOff ? 1U : 0); } rendererVisibilityMasks[instance.index] = (byte)visibilityMask; - rendererCrossFadeValues[instance.index] = (byte)crossFadeValue; + rendererMeshLodSettings[instance.index] = (byte)meshLodLevel; + rendererCrossFadeValues[instance.index] = (byte)(crossFadeValue & 0xFF); } } @@ -411,6 +548,7 @@ namespace UnityEngine.Rendering [ReadOnly] public NativeArray drawInstanceIndices; [ReadOnly] public CPUInstanceData.ReadOnly instanceData; [ReadOnly] public NativeArray rendererVisibilityMasks; + [ReadOnly] public NativeArray rendererMeshLodSettings; [NativeDisableContainerSafetyRestriction, NoAlias] [WriteOnly] public NativeArray batchBinAllocOffsets; [NativeDisableContainerSafetyRestriction, NoAlias] [WriteOnly] public NativeArray batchBinCounts; @@ -429,6 +567,29 @@ namespace UnityEngine.Rendering return instanceData.localToWorldIsFlippedBits.Get(instanceIndex); } + // Keep in sync with isMeshLodVisible from DrawCommandOutputPerBatch + private bool IsMeshLodVisible(int batchLodLevel, int rendererIndex, bool supportsCrossFade) + { + if (batchLodLevel < 0) + return true; + + var meshLodLevel = rendererMeshLodSettings[rendererIndex]; + var instanceLodLevel = meshLodLevel & ~CullingJob.k_MeshLodCrossfadeBits; + if (batchLodLevel == instanceLodLevel) + return true; + + if (!supportsCrossFade) + return false; + + var crossfadeBits = (meshLodLevel & CullingJob.k_MeshLodCrossfadeBits); + if (crossfadeBits == 0) + return false; + + // This sets sign to 1 if the 8th bit (e.g. k_MeshCrossfadeSignBit is set), and -1 otherwise. + var sign = (int)(crossfadeBits - CullingJob.k_MeshLodCrossfadeSignBit) >> 6; + + return batchLodLevel == instanceLodLevel + sign; + } static int GetPrimitiveCount(int indexCount, MeshTopology topology, bool nativeQuads) { @@ -463,13 +624,19 @@ namespace UnityEngine.Rendering var drawBatch = drawBatches[batchIndex]; var instanceCount = drawBatch.instanceCount; var instanceOffset = drawBatch.instanceOffset; + var supportsCrossFade = (drawBatch.key.flags & BatchDrawCommandFlags.LODCrossFadeKeyword) != 0; for (int i = 0; i < instanceCount; ++i) { var rendererIndex = drawInstanceIndices[instanceOffset + i]; bool isFlipped = IsInstanceFlipped(rendererIndex); int visibilityMask = (int)rendererVisibilityMasks[rendererIndex]; - if (visibilityMask == 0) + + bool isVisible = (visibilityMask != 0); + if (!isVisible) + continue; + + if (!IsMeshLodVisible(drawBatch.key.activeMeshLod, rendererIndex, supportsCrossFade)) continue; int configIndex = (int)(visibilityMask << 1) | (isFlipped ? 1 : 0); @@ -738,6 +905,7 @@ namespace UnityEngine.Rendering [ReadOnly] public CPUInstanceData.ReadOnly instanceData; [ReadOnly] public NativeArray rendererVisibilityMasks; + [ReadOnly] public NativeArray rendererMeshLodSettings; [ReadOnly] public NativeArray rendererCrossFadeValues; [ReadOnly] [DeallocateOnJobCompletion] public NativeArray batchBinAllocOffsets; @@ -757,11 +925,15 @@ namespace UnityEngine.Rendering [NativeDisableContainerSafetyRestriction, NoAlias] public NativeArray indirectDrawInfoGlobalArray; [NativeDisableContainerSafetyRestriction, NoAlias] public NativeArray indirectInstanceInfoGlobalArray; - unsafe int EncodeGPUInstanceIndexAndCrossFade(int rendererIndex, bool negateCrossFade) + int EncodeGPUInstanceIndexAndCrossFade(int rendererIndex, bool negateCrossFade) { var gpuInstanceIndex = instanceDataBuffer.CPUInstanceToGPUInstance(InstanceHandle.FromInt(rendererIndex)); - int crossFadeValue = rendererCrossFadeValues[rendererIndex]; - crossFadeValue -= 127; + var crossFadeValue = (int)rendererCrossFadeValues[rendererIndex]; + + if (crossFadeValue == CullingJob.k_LODFadeOff) + return gpuInstanceIndex.index; + + crossFadeValue -= (int)CullingJob.k_LODFadeZeroPacked; if (negateCrossFade) crossFadeValue = -crossFadeValue; gpuInstanceIndex.index |= crossFadeValue << 24; @@ -775,6 +947,32 @@ namespace UnityEngine.Rendering return instanceData.localToWorldIsFlippedBits.Get(instanceIndex); } + // This must be kept in sync with IsMeshLodVisible from binning pass + private bool IsMeshLodVisible(int batchLodLevel, int rendererIndex, bool supportsCrossFade, ref bool negateCrossfade) + { + if (batchLodLevel < 0) + return true; + + var meshLodSetting = rendererMeshLodSettings[rendererIndex]; + var instanceLodLevel = meshLodSetting & ~CullingJob.k_MeshLodCrossfadeBits; + if (batchLodLevel == instanceLodLevel) + return true; + + if (!supportsCrossFade) + return false; + + var crossfadeBits = (meshLodSetting & CullingJob.k_MeshLodCrossfadeBits); + if (crossfadeBits == 0) + return false; + + // This sets sign to 1 if the 8th bit (e.g. k_MeshLodCrossfadeSignBit is set), and -1 otherwise. + var sign = (int)(crossfadeBits - CullingJob.k_MeshLodCrossfadeSignBit) >> 6; + + negateCrossfade = true; + + return batchLodLevel == instanceLodLevel + sign; + } + unsafe public void Execute(int batchIndex) { DrawBatch drawBatch = drawBatches[batchIndex]; @@ -833,10 +1031,17 @@ namespace UnityEngine.Rendering int visibilityMask = configIndex >> 1; if (binningConfig.supportsCrossFade) { - if ((visibilityMask & 1) != 0) + var crossFadeVisibilityBit = (visibilityMask & 1); + if (crossFadeVisibilityBit == 0) + drawFlags &= ~BatchDrawCommandFlags.LODCrossFadeKeyword; + else drawFlags |= BatchDrawCommandFlags.LODCrossFadeKeyword; visibilityMask >>= 1; } + else + { + drawFlags &= ~BatchDrawCommandFlags.LODCrossFadeKeyword; + } if (binningConfig.supportsMotionCheck) { if ((visibilityMask & 1) != 0 && rangeSupportsMotion) @@ -909,6 +1114,7 @@ namespace UnityEngine.Rendering sortingPosition = sortingPosition, meshID = drawBatch.key.meshID, submeshIndex = (ushort)drawBatch.key.submeshIndex, + activeMeshLod = (ushort)drawBatch.key.activeMeshLod, }; } } @@ -916,6 +1122,7 @@ namespace UnityEngine.Rendering // write the visible instances var instanceOffset = drawBatch.instanceOffset; var instanceCount = drawBatch.instanceCount; + var supportsCrossFade = (drawBatch.key.flags & BatchDrawCommandFlags.LODCrossFadeKeyword) != 0; var lastRendererIndex = 0; if (binCount > 1) { @@ -925,7 +1132,13 @@ namespace UnityEngine.Rendering bool isFlipped = IsInstanceFlipped(rendererIndex); int visibilityMask = (int)rendererVisibilityMasks[rendererIndex]; - if (visibilityMask == 0) + + bool isVisible = (visibilityMask != 0); + if (!isVisible) + continue; + + bool negateCrossFade = false; + if (!IsMeshLodVisible(drawBatch.key.activeMeshLod, rendererIndex, supportsCrossFade, ref negateCrossFade)) continue; lastRendererIndex = rendererIndex; @@ -936,6 +1149,8 @@ namespace UnityEngine.Rendering var visibleInstanceOffset = instanceOffsetPerConfig[configIndex]; instanceOffsetPerConfig[configIndex]++; + var instanceIndexAndCrossFade = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, negateCrossFade); + if (isIndirect) { #if DEBUG @@ -952,7 +1167,7 @@ namespace UnityEngine.Rendering indirectInstanceInfoGlobalArray[indirectAllocInfo.instanceAllocIndex + visibleInstanceOffset] = new IndirectInstanceInfo { drawOffsetAndSplitMask = (drawCommandOffsetPerConfig[configIndex] << 8) | visibilityMask, - instanceIndexAndCrossFade = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, false), + instanceIndexAndCrossFade = instanceIndexAndCrossFade, }; } else @@ -961,7 +1176,7 @@ namespace UnityEngine.Rendering if (visibleInstanceOffset >= output.visibleInstanceCount) throw new Exception("Exceeding visible instance count"); #endif - output.visibleInstances[visibleInstanceOffset] = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, false); + output.visibleInstances[visibleInstanceOffset] = instanceIndexAndCrossFade; } } } @@ -977,7 +1192,15 @@ namespace UnityEngine.Rendering if (!isVisible) continue; + bool negateCrossFade = false; + if (!IsMeshLodVisible(drawBatch.key.activeMeshLod, rendererIndex, supportsCrossFade, ref negateCrossFade)) + continue; + lastRendererIndex = rendererIndex; + + var instanceIndexAndCrossFade = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, negateCrossFade); + + // only one bin for this batch if (isIndirect) { // remove extra bits so that the visibility mask is just the view mask @@ -989,12 +1212,12 @@ namespace UnityEngine.Rendering indirectInstanceInfoGlobalArray[indirectAllocInfo.instanceAllocIndex + visibleInstanceOffset] = new IndirectInstanceInfo { drawOffsetAndSplitMask = (batchDrawCommandOffset << 8) | visibilityMask, - instanceIndexAndCrossFade = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, false), + instanceIndexAndCrossFade = instanceIndexAndCrossFade, }; } else { - output.visibleInstances[visibleInstanceOffset] = EncodeGPUInstanceIndexAndCrossFade(rendererIndex, false); + output.visibleInstances[visibleInstanceOffset] = instanceIndexAndCrossFade; } visibleInstanceOffset++; } @@ -1063,6 +1286,7 @@ namespace UnityEngine.Rendering [ReadOnly] public GPUInstanceDataBuffer.ReadOnly instanceDataBuffer; [ReadOnly] public NativeArray rendererVisibilityMasks; + [ReadOnly] public NativeArray rendererMeshLodSettings; [ReadOnly] public NativeArray rendererCrossFadeValues; [ReadOnly] public CPUInstanceData.ReadOnly instanceData; @@ -1122,6 +1346,8 @@ namespace UnityEngine.Rendering { var rendererIndex = drawInstanceIndices[instanceOffset + i]; var visibilityMask = rendererVisibilityMasks[rendererIndex]; + if (drawBatch.key.activeMeshLod >= 0 && drawBatch.key.activeMeshLod != rendererMeshLodSettings[rendererIndex]) + visibilityMask = 0; if (visibilityMask == 0) continue; @@ -1494,6 +1720,13 @@ namespace UnityEngine.Rendering internal struct InstanceCuller : IDisposable { + private struct AnimatedFadeData + { + public int cameraID; + public JobHandle jobHandle; + } + + private NativeParallelHashMap m_LODParamsToCameraID; //@ Move this in CPUInstanceData. private ParallelBitArray m_CompactedVisibilityMasks; private JobHandle m_CompactedVisibilityMasksJobsHandle; @@ -1556,17 +1789,66 @@ namespace UnityEngine.Rendering m_CommandBuffer = new CommandBuffer(); m_CommandBuffer.name = "EnsureValidOcclusionTestResults"; + + m_LODParamsToCameraID = new NativeParallelHashMap(16, Allocator.Persistent); + } + + + // This relies on the fact that camera culling is scheduled ahead of shadow culling. + private JobHandle AnimateCrossFades(CPUPerCameraInstanceData perCameraInstanceData, BatchCullingContext cc, out CPUPerCameraInstanceData.PerCameraInstanceDataArrays cameraInstanceData, out bool hasAnimatedCrossfade) + { + var lodHash = cc.lodParameters.GetHashCode(); + hasAnimatedCrossfade = m_LODParamsToCameraID.TryGetValue(lodHash, out var animatedFadeData); + + if (hasAnimatedCrossfade) + { + cameraInstanceData = perCameraInstanceData.perCameraData[animatedFadeData.cameraID]; + Assert.IsTrue(cameraInstanceData.IsCreated); + return animatedFadeData.jobHandle; + } + + if (cc.viewType != BatchCullingViewType.Camera && !hasAnimatedCrossfade) + { + // For picking / filtering and outlining passes. We do not have animated crossfade data. + cameraInstanceData = new CPUPerCameraInstanceData.PerCameraInstanceDataArrays(); + return new JobHandle(); + } + + //For main camera, animate crossfades, and store the result in the hashmap to be retrieved by other cameras + var viewID = cc.viewID.GetInstanceID(); + + hasAnimatedCrossfade = perCameraInstanceData.perCameraData.TryGetValue(viewID, out var tmpCameraInstanceData); + if (hasAnimatedCrossfade == false) + { + // For picking / filtering and outlining passes. We do not have animated crossfade data. + cameraInstanceData = new CPUPerCameraInstanceData.PerCameraInstanceDataArrays(); + return new JobHandle(); + } + + cameraInstanceData = tmpCameraInstanceData; + Assert.IsTrue(cameraInstanceData.IsCreated); + + var handle = new AnimateCrossFadeJob() + { + deltaTime = Time.deltaTime, + crossFadeArray = cameraInstanceData.crossFades + }.Schedule(perCameraInstanceData.instancesLength, AnimateCrossFadeJob.k_BatchSize); + + m_LODParamsToCameraID.TryAdd(lodHash, new AnimatedFadeData(){ cameraID = viewID, jobHandle = handle}); + return handle; } private unsafe JobHandle CreateFrustumCullingJob( in BatchCullingContext cc, in CPUInstanceData.ReadOnly instanceData, in CPUSharedInstanceData.ReadOnly sharedInstanceData, + in CPUPerCameraInstanceData perCameraInstanceData, NativeList lodGroupCullingData, in BinningConfig binningConfig, float smallMeshScreenPercentage, OcclusionCullingCommon occlusionCullingCommon, NativeArray rendererVisibilityMasks, + NativeArray rendererMeshLodSettings, NativeArray rendererCrossFadeValues) { Assert.IsTrue(cc.cullingSplits.Length <= 6, "InstanceCuller supports up to 6 culling splits."); @@ -1575,16 +1857,19 @@ namespace UnityEngine.Rendering ReceiverSphereCuller receiverSphereCuller; FrustumPlaneCuller frustumPlaneCuller; float screenRelativeMetric; + float meshLodConstant; fixed (BatchCullingContext* contextPtr = &cc) { - InstanceCullerBurst.SetupCullingJobInput(QualitySettings.lodBias, contextPtr, &receiverPlanes, &receiverSphereCuller, - &frustumPlaneCuller, &screenRelativeMetric); + InstanceCullerBurst.SetupCullingJobInput(QualitySettings.lodBias, QualitySettings.meshLodThreshold, contextPtr, &receiverPlanes, &receiverSphereCuller, + &frustumPlaneCuller, &screenRelativeMetric, &meshLodConstant); } if (occlusionCullingCommon != null) occlusionCullingCommon.UpdateSilhouettePlanes(cc.viewID.GetInstanceID(), receiverPlanes.SilhouettePlaneSubArray()); + var jobHandle = AnimateCrossFades(perCameraInstanceData, cc, out var cameraInstanceData, out var hasAnimatedCrossfade); + var cullingJob = new CullingJob { binningConfig = binningConfig, @@ -1596,20 +1881,23 @@ namespace UnityEngine.Rendering worldToLightSpaceRotation = receiverSphereCuller.worldToLightSpaceRotation, cullLightmappedShadowCasters = (cc.cullingFlags & BatchCullingFlags.CullLightmappedShadowCasters) != 0, cameraPosition = cc.lodParameters.cameraPosition, + sqrMeshLodSelectionConstant = meshLodConstant * meshLodConstant, sqrScreenRelativeMetric = screenRelativeMetric * screenRelativeMetric, minScreenRelativeHeight = smallMeshScreenPercentage * 0.01f, isOrtho = cc.lodParameters.isOrthographic, + animateCrossFades = hasAnimatedCrossfade, instanceData = instanceData, sharedInstanceData = sharedInstanceData, + cameraInstanceData = cameraInstanceData, lodGroupCullingData = lodGroupCullingData, occlusionBuffer = cc.occlusionBuffer, rendererVisibilityMasks = rendererVisibilityMasks, + rendererMeshLodSettings = rendererMeshLodSettings, rendererCrossFadeValues = rendererCrossFadeValues, maxLOD = QualitySettings.maximumLODLevel, cullingLayerMask = cc.cullingLayerMask, sceneCullingMask = cc.sceneCullingMask, - - }.Schedule(instanceData.instancesLength, CullingJob.k_BatchSize); + }.Schedule(instanceData.instancesLength, CullingJob.k_BatchSize, jobHandle); receiverPlanes.Dispose(cullingJob); frustumPlaneCuller.Dispose(cullingJob); @@ -1621,14 +1909,14 @@ namespace UnityEngine.Rendering private int ComputeWorstCaseDrawCommandCount( in BatchCullingContext cc, BinningConfig binningConfig, - CPUDrawInstanceData drawInstanceData, - int crossFadedRendererCount) + CPUDrawInstanceData drawInstanceData) { int visibleInstancesCount = drawInstanceData.drawInstances.Length; int drawCommandCount = drawInstanceData.drawBatches.Length; // add the number of batches split due to actively cross-fading - drawCommandCount += math.min(crossFadedRendererCount, drawCommandCount); + if (binningConfig.supportsCrossFade) + drawCommandCount *= 2; // batches can be split due to flip winding drawCommandCount *= 2; @@ -1656,11 +1944,11 @@ namespace UnityEngine.Rendering BatchCullingOutput cullingOutput, in CPUInstanceData.ReadOnly instanceData, in CPUSharedInstanceData.ReadOnly sharedInstanceData, + in CPUPerCameraInstanceData perCameraInstanceData, in GPUInstanceDataBuffer.ReadOnly instanceDataBuffer, NativeList lodGroupCullingData, CPUDrawInstanceData drawInstanceData, NativeParallelHashMap batchIDs, - int crossFadedRendererCount, float smallMeshScreenPercentage, OcclusionCullingCommon occlusionCullingCommon) { @@ -1676,16 +1964,17 @@ namespace UnityEngine.Rendering var binningConfig = new BinningConfig { viewCount = cc.cullingSplits.Length, - supportsCrossFade = (crossFadedRendererCount > 0), + supportsCrossFade = QualitySettings.enableLODCrossFade, supportsMotionCheck = (cc.viewType == BatchCullingViewType.Camera), // TODO: could disable here if RP never needs object motion vectors, for now always batch on it }; var visibilityLength = instanceData.handlesLength; var rendererVisibilityMasks = new NativeArray(visibilityLength, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var rendererCrossFadeValues = new NativeArray(visibilityLength, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); + var rendererMeshLodSettings = new NativeArray(visibilityLength, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); - var cullingJobHandle = CreateFrustumCullingJob(cc, instanceData, sharedInstanceData, lodGroupCullingData, binningConfig, - smallMeshScreenPercentage, occlusionCullingCommon, rendererVisibilityMasks, rendererCrossFadeValues); + var cullingJobHandle = CreateFrustumCullingJob(cc, instanceData, sharedInstanceData, perCameraInstanceData, lodGroupCullingData, binningConfig, + smallMeshScreenPercentage, occlusionCullingCommon, rendererVisibilityMasks, rendererMeshLodSettings, rendererCrossFadeValues); #if UNITY_EDITOR // Unfortunately BatchCullingContext doesn't provide full visibility and picking context. @@ -1701,13 +1990,13 @@ namespace UnityEngine.Rendering { // This outputs picking draw commands for the objects that can be picked. cullingJobHandle = CreatePickingCullingOutputJob_EditorOnly(cc, cullingOutput, instanceData, sharedInstanceData, instanceDataBuffer, - drawInstanceData, batchIDs, rendererVisibilityMasks, rendererCrossFadeValues, cullingJobHandle); + drawInstanceData, batchIDs, rendererVisibilityMasks, rendererMeshLodSettings, rendererCrossFadeValues, cullingJobHandle); } else if (cc.viewType == BatchCullingViewType.Filtering) { // This outputs draw commands for the objects filtered by search input in the hierarchy on in the scene view. - cullingJobHandle = CreateFilteringCullingOutputJob_EditorOnly(cc, cullingOutput, instanceData, sharedInstanceData, instanceDataBuffer, drawInstanceData, - batchIDs, rendererVisibilityMasks, rendererCrossFadeValues, cullingJobHandle); + cullingJobHandle = CreateFilteringCullingOutputJob_EditorOnly(cc, cullingOutput, instanceData, sharedInstanceData, instanceDataBuffer, + drawInstanceData, batchIDs, rendererVisibilityMasks, rendererMeshLodSettings, rendererCrossFadeValues, cullingJobHandle); } #endif // This outputs regular draw commands. @@ -1722,7 +2011,7 @@ namespace UnityEngine.Rendering } var batchCount = drawInstanceData.drawBatches.Length; - int maxBinCount = ComputeWorstCaseDrawCommandCount(cc, binningConfig, drawInstanceData, crossFadedRendererCount); + int maxBinCount = ComputeWorstCaseDrawCommandCount(cc, binningConfig, drawInstanceData); var batchBinAllocOffsets = new NativeArray(batchCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var batchBinCounts = new NativeArray(batchCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); @@ -1751,6 +2040,7 @@ namespace UnityEngine.Rendering drawInstanceIndices = drawInstanceData.drawInstanceIndices, instanceData = instanceData, rendererVisibilityMasks = rendererVisibilityMasks, + rendererMeshLodSettings = rendererMeshLodSettings, batchBinAllocOffsets = batchBinAllocOffsets, batchBinCounts = batchBinCounts, binAllocCounter = binAllocCounter, @@ -1790,6 +2080,7 @@ namespace UnityEngine.Rendering drawInstanceIndices = drawInstanceData.drawInstanceIndices, instanceData = instanceData, rendererVisibilityMasks = rendererVisibilityMasks, + rendererMeshLodSettings = rendererMeshLodSettings, rendererCrossFadeValues = rendererCrossFadeValues, batchBinAllocOffsets = batchBinAllocOffsets, batchBinCounts = batchBinCounts, @@ -1816,6 +2107,7 @@ namespace UnityEngine.Rendering cullingJobHandle = rendererVisibilityMasks.Dispose(cullingJobHandle); cullingJobHandle = rendererCrossFadeValues.Dispose(cullingJobHandle); + cullingJobHandle = rendererMeshLodSettings.Dispose(cullingJobHandle); return cullingJobHandle; } @@ -1889,7 +2181,7 @@ namespace UnityEngine.Rendering private JobHandle CreateFilteringCullingOutputJob_EditorOnly(in BatchCullingContext cc, BatchCullingOutput cullingOutput, in CPUInstanceData.ReadOnly instanceData, in CPUSharedInstanceData.ReadOnly sharedInstanceData, in GPUInstanceDataBuffer.ReadOnly instanceDataBuffer, - in CPUDrawInstanceData drawInstanceData, NativeParallelHashMap batchIDs, NativeArray rendererVisibilityMasks, + in CPUDrawInstanceData drawInstanceData, NativeParallelHashMap batchIDs, NativeArray rendererVisibilityMasks, NativeArray rendererMeshLodSettings, NativeArray rendererCrossFadeValues, JobHandle cullingJobHandle) { NativeArray filteredRenderers = new NativeArray(sharedInstanceData.rendererGroupIDs.Length, Allocator.TempJob); @@ -1902,6 +2194,7 @@ namespace UnityEngine.Rendering batchIDs = batchIDs, instanceDataBuffer = instanceDataBuffer, rendererVisibilityMasks = rendererVisibilityMasks, + rendererMeshLodSettings = rendererMeshLodSettings, rendererCrossFadeValues = rendererCrossFadeValues, instanceData = instanceData, sharedInstanceData = sharedInstanceData, @@ -1926,6 +2219,7 @@ namespace UnityEngine.Rendering private JobHandle CreatePickingCullingOutputJob_EditorOnly(in BatchCullingContext cc, BatchCullingOutput cullingOutput, in CPUInstanceData.ReadOnly instanceData, in CPUSharedInstanceData.ReadOnly sharedInstanceData, in GPUInstanceDataBuffer.ReadOnly instanceDataBuffer, in CPUDrawInstanceData drawInstanceData, NativeParallelHashMap batchIDs, NativeArray rendererVisibilityMasks, + NativeArray rendererMeshLodSettings, NativeArray rendererCrossFadeValues, JobHandle cullingJobHandle) { // GPUResindetDrawer doesn't handle rendering of persistent game objects like prefabs. They are rendered by SRP. @@ -1943,6 +2237,7 @@ namespace UnityEngine.Rendering batchIDs = batchIDs, instanceDataBuffer = instanceDataBuffer, rendererVisibilityMasks = rendererVisibilityMasks, + rendererMeshLodSettings = rendererMeshLodSettings, rendererCrossFadeValues = rendererCrossFadeValues, instanceData = instanceData, sharedInstanceData = sharedInstanceData, @@ -1968,7 +2263,6 @@ namespace UnityEngine.Rendering } #endif - public void InstanceOccludersUpdated(int viewInstanceID, int subviewMask, RenderersBatchersContext batchersContext) { if (m_DebugStats?.enabled ?? false) @@ -2314,10 +2608,12 @@ namespace UnityEngine.Rendering #endif } - public void UpdateFrame() + public void UpdateFrame(int cameraCount) { - DisposeSceneViewHiddenBits(); DisposeCompactVisibilityMasks(); + if (cameraCount > m_LODParamsToCameraID.Capacity) + m_LODParamsToCameraID.Capacity = cameraCount; + m_LODParamsToCameraID.Clear(); FlushDebugCounters(); m_IndirectStorage.ClearContextsAndGrowBuffers(); } @@ -2345,6 +2641,7 @@ namespace UnityEngine.Rendering m_ShaderVariables.Dispose(); m_ConstantBuffer.Release(); m_CommandBuffer.Dispose(); + m_LODParamsToCameraID.Dispose(); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs index d123762d..fc4c27e8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullerBurst.cs @@ -7,13 +7,16 @@ namespace UnityEngine.Rendering 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) + public static unsafe void SetupCullingJobInput(float lodBias, float meshLodThreshold, BatchCullingContext* context, + ReceiverPlanes* receiverPlanes, ReceiverSphereCuller* receiverSphereCuller, FrustumPlaneCuller* frustumPlaneCuller, + float* screenRelativeMetric, float* meshLodConstant) { *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); + *screenRelativeMetric = LODRenderingUtils.CalculateScreenRelativeMetricNoBias(context->lodParameters); + *meshLodConstant = LODRenderingUtils.CalculateMeshLodConstant(context->lodParameters, *screenRelativeMetric, meshLodThreshold); + *screenRelativeMetric /= lodBias; } } } 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 c2b526d2..7bac52df 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcher.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using UnityEngine.Assertions; +using Unity.Mathematics; using Unity.Collections; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; @@ -289,74 +290,6 @@ namespace UnityEngine.Rendering } } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] - internal struct RemoveDrawInstanceIndicesJob : IJob - { - [NativeDisableContainerSafetyRestriction, NoAlias] [ReadOnly] public NativeArray drawInstanceIndices; - - public NativeList drawInstances; - public NativeParallelHashMap rangeHash; - public NativeParallelHashMap batchHash; - public NativeList drawRanges; - public NativeList drawBatches; - - public void RemoveDrawRange(in RangeKey key) - { - int drawRangeIndex = rangeHash[key]; - - ref DrawRange lastDrawRange = ref drawRanges.ElementAt(drawRanges.Length - 1); - rangeHash[lastDrawRange.key] = drawRangeIndex; - - rangeHash.Remove(key); - drawRanges.RemoveAtSwapBack(drawRangeIndex); - } - - public void RemoveDrawBatch(in DrawKey key) - { - int drawBatchIndex = batchHash[key]; - - ref DrawBatch drawBatch = ref drawBatches.ElementAt(drawBatchIndex); - - 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 DrawBatch lastDrawBatch = ref drawBatches.ElementAt(drawBatches.Length - 1); - batchHash[lastDrawBatch.key] = drawBatchIndex; - - batchHash.Remove(key); - drawBatches.RemoveAtSwapBack(drawBatchIndex); - } - - public unsafe void Execute() - { - 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); - - UnsafeUtility.MemCpy(drawInstance, drawInstancesPtr + drawInstancesNewBack--, sizeof(DrawInstance)); - } - - drawInstances.ResizeUninitialized(drawInstancesNewBack + 1); - } - } - [BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)] internal struct UpdatePackedMaterialDataCacheJob : IJob { @@ -736,11 +669,11 @@ namespace UnityEngine.Rendering cullingOutput, m_BatchersContext.instanceData, m_BatchersContext.sharedInstanceData, + m_BatchersContext.perCameraInstanceData, m_BatchersContext.instanceDataBuffer, m_BatchersContext.lodGroupCullingData, m_DrawInstanceData, m_GlobalBatchIDs, - m_BatchersContext.crossfadedRendererCount, m_BatchersContext.smallMeshScreenPercentage, allowOcclusionCulling ? m_BatchersContext.occlusionCullingCommon : null); @@ -924,7 +857,7 @@ namespace UnityEngine.Rendering public void UpdateFrame() { - m_Culler.UpdateFrame(); + m_Culler.UpdateFrame(m_BatchersContext.cameraCount); } public ParallelBitArray GetCompactedVisibilityMasks(bool syncCullingJobs) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs index b3e353d6..f429d38b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceCullingBatcherBurst.cs @@ -118,6 +118,7 @@ namespace UnityEngine.Rendering { var meshIndex = rendererData.meshIndex[i]; var meshID = rendererData.meshID[meshIndex]; + var meshLodInfo = rendererData.meshLodInfo[meshIndex]; var submeshCount = rendererData.subMeshCount[meshIndex]; var subMeshDescOffset = rendererData.subMeshDescOffset[meshIndex]; var batchMeshID = batchMeshHash[meshID]; @@ -195,7 +196,7 @@ namespace UnityEngine.Rendering { var materialID = rendererData.materialID[materialIndex]; bool isFound = packedMaterialDataHash.TryGetValue(materialID, out packedMaterialData); - Assert.IsTrue(isFound, "Packed material data not found."); + Assert.IsTrue(isFound); } supportsIndirect &= packedMaterialData.isIndirectSupported; @@ -249,14 +250,21 @@ namespace UnityEngine.Rendering if (packedMaterialData.isTransparent) flags |= BatchDrawCommandFlags.HasSortingPosition; + if (packedMaterialData.supportsCrossFade) + flags |= BatchDrawCommandFlags.LODCrossFadeKeyword; + + int lodLoopCount = math.max(meshLodInfo.levelCount, 1); + + for (int lodLoopIndex = 0; lodLoopIndex < lodLoopCount; ++lodLoopIndex) { var submeshIndex = startSubMesh + matIndex; - var subMeshDesc = rendererData.subMeshDesc[subMeshDescOffset + submeshIndex]; + var subMeshDesc = rendererData.subMeshDesc[subMeshDescOffset + submeshIndex*lodLoopCount + lodLoopIndex]; var drawKey = new DrawKey { materialID = batchMaterialID, meshID = batchMeshID, submeshIndex = submeshIndex, + activeMeshLod = meshLodInfo.lodSelectionActive ? lodLoopIndex : -1, flags = flags, transparentInstanceId = packedMaterialData.isTransparent ? rendererGroupID : 0, range = rangeKey, diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceData.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceData.cs index f20b2891..8572ba3b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceData.cs @@ -26,6 +26,7 @@ namespace UnityEngine.Rendering public ParallelBitArray movedInPreviousFrameBits; public ParallelBitArray visibleInPreviousFrameBits; public EditorInstanceDataArrays editorData; + public NativeArray meshLodData; public int instancesLength { get => m_StructData[0]; set => m_StructData[0] = value; } public int instancesCapacity { get => m_StructData[1]; set => m_StructData[1] = value; } @@ -48,6 +49,7 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits = new ParallelBitArray(instancesCapacity, Allocator.Persistent); visibleInPreviousFrameBits = new ParallelBitArray(instancesCapacity, Allocator.Persistent); editorData.Initialize(initCapacity); + meshLodData = new NativeArray(instancesCapacity, Allocator.Persistent); } public void Dispose() @@ -63,6 +65,7 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits.Dispose(); visibleInPreviousFrameBits.Dispose(); editorData.Dispose(); + meshLodData.Dispose(); } private void Grow(int newCapacity) @@ -81,6 +84,7 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits.Resize(newCapacity); visibleInPreviousFrameBits.Resize(newCapacity); editorData.Grow(newCapacity); + meshLodData.ResizeArray(newCapacity); instancesCapacity = newCapacity; } @@ -185,6 +189,7 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits.Set(index, movedInPreviousFrameBits.Get(lastIndex)); visibleInPreviousFrameBits.Set(index, visibleInPreviousFrameBits.Get(lastIndex)); editorData.Remove(index, lastIndex); + meshLodData[index] = meshLodData[lastIndex]; m_InstanceIndices[instances[lastIndex].index] = index; m_InstanceIndices[instance.index] = k_InvalidIndex; @@ -192,7 +197,7 @@ namespace UnityEngine.Rendering } public void Set(InstanceHandle instance, SharedInstanceHandle sharedInstance, bool localToWorldIsFlipped, in AABB worldAABB, int tetrahedronCacheIndex, - bool movedInCurrentFrame, bool movedInPreviousFrame, bool visibleInPreviousFrame) + bool movedInCurrentFrame, bool movedInPreviousFrame, bool visibleInPreviousFrame, in GPUDrivenRendererMeshLodData meshLod) { int index = InstanceToIndex(instance); sharedInstances[index] = sharedInstance; @@ -203,11 +208,12 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits.Set(index, movedInPreviousFrame); visibleInPreviousFrameBits.Set(index, visibleInPreviousFrame); editorData.SetDefault(index); + meshLodData[index] = meshLod; } public void SetDefault(InstanceHandle instance) { - Set(instance, SharedInstanceHandle.Invalid, false, new AABB(), k_InvalidIndex, false, false, false); + Set(instance, SharedInstanceHandle.Invalid, false, new AABB(), k_InvalidIndex, false, false, false, new GPUDrivenRendererMeshLodData()); } // These accessors just for convenience and additional safety. @@ -220,6 +226,7 @@ namespace UnityEngine.Rendering public bool Get_MovedInCurrentFrame(InstanceHandle instance) { return movedInCurrentFrameBits.Get(InstanceToIndex(instance)); } public bool Get_MovedInPreviousFrame(InstanceHandle instance) { return movedInPreviousFrameBits.Get(InstanceToIndex(instance)); } public bool Get_VisibleInPreviousFrame(InstanceHandle instance) { return visibleInPreviousFrameBits.Get(InstanceToIndex(instance)); } + public GPUDrivenRendererMeshLodData Get_MeshLodData(InstanceHandle instance) { return meshLodData[InstanceToIndex(instance)]; } public void Set_SharedInstance(InstanceHandle instance, SharedInstanceHandle sharedInstance) { sharedInstances[InstanceToIndex(instance)] = sharedInstance; } public void Set_LocalToWorldIsFlipped(InstanceHandle instance, bool isFlipped) { localToWorldIsFlippedBits.Set(InstanceToIndex(instance), isFlipped); } @@ -228,6 +235,7 @@ namespace UnityEngine.Rendering public void Set_MovedInCurrentFrame(InstanceHandle instance, bool movedInCurrentFrame) { movedInCurrentFrameBits.Set(InstanceToIndex(instance), movedInCurrentFrame); } public void Set_MovedInPreviousFrame(InstanceHandle instance, bool movedInPreviousFrame) { movedInPreviousFrameBits.Set(InstanceToIndex(instance), movedInPreviousFrame); } public void Set_VisibleInPreviousFrame(InstanceHandle instance, bool visibleInPreviousFrame) { visibleInPreviousFrameBits.Set(InstanceToIndex(instance), visibleInPreviousFrame); } + public void Set_MeshLodData(InstanceHandle instance, GPUDrivenRendererMeshLodData meshLod) { meshLodData[InstanceToIndex(instance)] = meshLod; } public ReadOnly AsReadOnly() { @@ -246,6 +254,7 @@ namespace UnityEngine.Rendering public readonly ParallelBitArray movedInPreviousFrameBits; public readonly ParallelBitArray visibleInPreviousFrameBits; public readonly EditorInstanceDataArrays.ReadOnly editorData; + public readonly NativeArray.ReadOnly meshLodData; public readonly int handlesLength => instanceIndices.Length; public readonly int instancesLength => instances.Length; @@ -261,6 +270,7 @@ namespace UnityEngine.Rendering movedInPreviousFrameBits = instanceData.movedInPreviousFrameBits.GetSubArray(instanceData.instancesLength);//.AsReadOnly(); // Implement later. visibleInPreviousFrameBits = instanceData.visibleInPreviousFrameBits.GetSubArray(instanceData.instancesLength);//.AsReadOnly(); // Implement later. editorData = new EditorInstanceDataArrays.ReadOnly(instanceData); + meshLodData = instanceData.meshLodData.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); } public int InstanceToIndex(InstanceHandle instance) @@ -297,6 +307,142 @@ namespace UnityEngine.Rendering } } + internal struct CPUPerCameraInstanceData : IDisposable + { + public const byte k_InvalidByteData = 0xff; + + public NativeParallelHashMap perCameraData; + + private NativeArray m_StructData; + public int instancesLength { get => m_StructData[0]; set => m_StructData[0] = value; } + public int instancesCapacity { get => m_StructData[1]; set => m_StructData[1] = value; } + + public int cameraCount { get { return perCameraData.Count();}} + + internal struct PerCameraInstanceDataArrays : IDisposable + { + internal UnsafeList meshLods; + internal UnsafeList crossFades; + + public bool IsCreated => meshLods.IsCreated && crossFades.IsCreated; + + public PerCameraInstanceDataArrays(int initCapacity) + { + meshLods = new UnsafeList(initCapacity, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + meshLods.Length = initCapacity; + crossFades = new UnsafeList(initCapacity, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + crossFades.Length = initCapacity; + } + + public void Dispose() + { + meshLods.Dispose(); + crossFades.Dispose(); + } + + internal void Remove(int index, int lastIndex) + { + meshLods[index] = meshLods[lastIndex]; + crossFades[index] = crossFades[lastIndex]; + } + + internal void Grow(int previousCapacity, int newCapacity) + { + meshLods.Length = newCapacity; + crossFades.Length = newCapacity; + } + + internal void SetDefault(int index) + { + meshLods[index] = k_InvalidByteData; + crossFades[index] = k_InvalidByteData; + } + } + + public void Initialize(int initCapacity) + { + perCameraData = new NativeParallelHashMap(1,Allocator.Persistent); + m_StructData = new NativeArray(2, Allocator.Persistent); + instancesCapacity = initCapacity; + instancesLength = 0; + } + + public void DeallocateCameras(NativeArray cameraIDs) + { + foreach (var cameraID in cameraIDs) + { + if (!perCameraData.TryGetValue(cameraID, out var perCameraInstanceData)) + continue; + + perCameraInstanceData.Dispose(); + perCameraData.Remove(cameraID); + } + } + + public void AllocateCameras(NativeArray cameraIDs) + { + foreach (var cameraID in cameraIDs) + { + if (perCameraData.TryGetValue(cameraID, out var cameraInstanceData)) + continue; + + cameraInstanceData = new PerCameraInstanceDataArrays(instancesCapacity); + perCameraData.Add(cameraID, cameraInstanceData); + } + } + + public void Remove(int index) + { + int lastIndex = instancesLength - 1; + + foreach (var pair in perCameraData) + { + pair.Value.Remove(index, lastIndex); + } + + instancesLength -= 1; + } + + public void IncreaseInstanceCount() + { + instancesLength++; + } + + public void Dispose() + { + foreach (var pair in perCameraData) + { + pair.Value.Dispose(); + } + + m_StructData.Dispose(); + perCameraData.Dispose(); + } + + internal void Grow(int newCapacity) + { + if(newCapacity < instancesCapacity) + return; + + var previousCapacity = instancesCapacity; + instancesCapacity = newCapacity; + + foreach (var pair in perCameraData) + { + pair.Value.Grow(previousCapacity, instancesCapacity); + } + } + + public void SetDefault(int index) + { + foreach (var pair in perCameraData) + { + pair.Value.SetDefault(index); + } + } + + } + internal struct CPUSharedInstanceData : IDisposable { private const int k_InvalidIndex = -1; @@ -316,6 +462,7 @@ namespace UnityEngine.Rendering public NativeArray localAABBs; public NativeArray flags; public NativeArray lodGroupAndMasks; + public NativeArray meshLodInfos; public NativeArray gameObjectLayers; public NativeArray refCounts; @@ -337,6 +484,7 @@ namespace UnityEngine.Rendering flags = new NativeArray(instancesCapacity, Allocator.Persistent); lodGroupAndMasks = new NativeArray(instancesCapacity, Allocator.Persistent); lodGroupAndMasks.FillArray(k_InvalidLODGroupAndMask); + meshLodInfos = new NativeArray(instancesCapacity, Allocator.Persistent); gameObjectLayers = new NativeArray(instancesCapacity, Allocator.Persistent); refCounts = new NativeArray(instancesCapacity, Allocator.Persistent); } @@ -358,6 +506,7 @@ namespace UnityEngine.Rendering localAABBs.Dispose(); flags.Dispose(); lodGroupAndMasks.Dispose(); + meshLodInfos.Dispose(); gameObjectLayers.Dispose(); refCounts.Dispose(); } @@ -376,6 +525,7 @@ namespace UnityEngine.Rendering flags.ResizeArray(newCapacity); lodGroupAndMasks.ResizeArray(newCapacity); lodGroupAndMasks.FillArray(k_InvalidLODGroupAndMask, instancesCapacity); + meshLodInfos.ResizeArray(newCapacity); gameObjectLayers.ResizeArray(newCapacity); refCounts.ResizeArray(newCapacity); @@ -492,6 +642,7 @@ namespace UnityEngine.Rendering localAABBs[index] = localAABBs[lastIndex]; flags[index] = flags[lastIndex]; lodGroupAndMasks[index] = lodGroupAndMasks[lastIndex]; + meshLodInfos[index] = meshLodInfos[lastIndex]; gameObjectLayers[index] = gameObjectLayers[lastIndex]; refCounts[index] = refCounts[lastIndex]; @@ -526,7 +677,7 @@ namespace UnityEngine.Rendering } public void Set(SharedInstanceHandle instance, int rendererGroupID, in SmallIntegerArray materialIDs, int meshID, in AABB localAABB, TransformUpdateFlags transformUpdateFlags, - InstanceFlags instanceFlags, uint lodGroupAndMask, int gameObjectLayer, int refCount) + InstanceFlags instanceFlags, uint lodGroupAndMask, GPUDrivenMeshLodInfo meshLodInfo, int gameObjectLayer, int refCount) { int index = SharedInstanceToIndex(instance); @@ -537,13 +688,14 @@ namespace UnityEngine.Rendering localAABBs[index] = localAABB; flags[index] = new CPUSharedInstanceFlags { transformUpdateFlags = transformUpdateFlags, instanceFlags = instanceFlags }; lodGroupAndMasks[index] = lodGroupAndMask; + meshLodInfos[index] = meshLodInfo; gameObjectLayers[index] = gameObjectLayer; refCounts[index] = refCount; } public void SetDefault(SharedInstanceHandle instance) { - Set(instance, 0, default, 0, new AABB(), TransformUpdateFlags.None, InstanceFlags.None, k_InvalidLODGroupAndMask, 0, 0); + Set(instance, 0, default, 0, new AABB(), TransformUpdateFlags.None, InstanceFlags.None, k_InvalidLODGroupAndMask, new GPUDrivenMeshLodInfo(), 0, 0); } public ReadOnly AsReadOnly() @@ -561,6 +713,7 @@ namespace UnityEngine.Rendering public readonly NativeArray.ReadOnly localAABBs; public readonly NativeArray.ReadOnly flags; public readonly NativeArray.ReadOnly lodGroupAndMasks; + public readonly NativeArray.ReadOnly meshLodInfos; public readonly NativeArray.ReadOnly gameObjectLayers; public readonly NativeArray.ReadOnly refCounts; public readonly int handlesLength => instanceIndices.Length; @@ -576,6 +729,7 @@ namespace UnityEngine.Rendering localAABBs = instanceData.localAABBs.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); flags = instanceData.flags.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); lodGroupAndMasks = instanceData.lodGroupAndMasks.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); + meshLodInfos = instanceData.meshLodInfos.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); gameObjectLayers = instanceData.gameObjectLayers.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); refCounts = instanceData.refCounts.GetSubArray(0, instanceData.instancesLength).AsReadOnly(); } @@ -765,7 +919,7 @@ namespace UnityEngine.Rendering AffectsLightmaps = 1 << 0, // either lightmapped or influence-only IsShadowsOff = 1 << 1, // shadow casting mode is ShadowCastingMode.Off IsShadowsOnly = 1 << 2, // shadow casting mode is ShadowCastingMode.ShadowsOnly - HasProgressiveLod = 1 << 3, + HasMeshLod = 1 << 3, SmallMeshCulling = 1 << 4 } 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 5de08a63..a31a90a4 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 @@ -494,6 +494,7 @@ namespace UnityEngine.Rendering [NativeDisableParallelForRestriction][NativeDisableContainerSafetyRestriction, NoAlias] public CPUInstanceData instanceData; [NativeDisableParallelForRestriction][NativeDisableContainerSafetyRestriction, NoAlias] public CPUSharedInstanceData sharedInstanceData; + [NativeDisableParallelForRestriction][NativeDisableContainerSafetyRestriction, NoAlias] public CPUPerCameraInstanceData perCameraInstanceData; public void Execute(int index) { @@ -508,6 +509,7 @@ namespace UnityEngine.Rendering int materialCount = rendererData.materialsCount[index]; int meshID = rendererData.meshID[meshIndex]; + var meshLodInfo = rendererData.meshLodInfo[meshIndex]; const int k_LightmapIndexMask = 0xFFFF; const int k_LightmapIndexNotLightmapped = 0xFFFF; @@ -542,6 +544,9 @@ namespace UnityEngine.Rendering break; } + if (meshLodInfo.lodSelectionActive) + instanceFlags |= InstanceFlags.HasMeshLod; + // If the object is light mapped, or has the special influence-only value, it affects lightmaps if (lmIndexMasked != k_LightmapIndexNotLightmapped) instanceFlags |= InstanceFlags.AffectsLightmaps; @@ -587,7 +592,7 @@ namespace UnityEngine.Rendering materialIDs[i] = materialInstanceID; } - sharedInstanceData.Set(sharedInstance, rendererGroupID, materialIDs, meshID, localAABB, transformUpdateFlags, instanceFlags, lodGroupAndMask, gameObjectLayer, + sharedInstanceData.Set(sharedInstance, rendererGroupID, materialIDs, meshID, localAABB, transformUpdateFlags, instanceFlags, lodGroupAndMask, meshLodInfo, gameObjectLayer, sharedInstanceData.Get_RefCount(sharedInstance)); for (int i = 0; i < instancesCount; ++i) @@ -604,6 +609,7 @@ namespace UnityEngine.Rendering bool isFlipped = (det < 0.0f); int instanceIndex = instanceData.InstanceToIndex(instance); + perCameraInstanceData.SetDefault(instanceIndex); instanceData.localToWorldIsFlippedBits.Set(instanceIndex, isFlipped); instanceData.worldAABBs[instanceIndex] = worldAABB; instanceData.tetrahedronCacheIndices[instanceIndex] = -1; @@ -611,6 +617,7 @@ namespace UnityEngine.Rendering instanceData.editorData.sceneCullingMasks[instanceIndex] = rendererData.editorData[index].sceneCullingMask; // Store more editor instance data here if needed. #endif + instanceData.meshLodData[instanceIndex] = rendererData.meshLodData[index]; } } } 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 1649aeec..7db7f119 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 @@ -13,6 +13,7 @@ namespace UnityEngine.Rendering private InstanceAllocators m_InstanceAllocators; private CPUSharedInstanceData m_SharedInstanceData; private CPUInstanceData m_InstanceData; + private CPUPerCameraInstanceData m_PerCameraInstanceData; //@ We may want something a bit faster instead of multi hash map. Remove and search performance for multiple instances per renderer group is not great. private NativeParallelMultiHashMap m_RendererGroupInstanceMultiHash; @@ -39,6 +40,8 @@ namespace UnityEngine.Rendering public bool hasBoundingSpheres { get { return m_EnableBoundingSpheres; } } public CPUInstanceData.ReadOnly instanceData { get { return m_InstanceData.AsReadOnly(); } } + public CPUPerCameraInstanceData perCameraInstanceData { get { return m_PerCameraInstanceData; } } + public int cameraCount { get { return m_PerCameraInstanceData.cameraCount; }} public CPUSharedInstanceData.ReadOnly sharedInstanceData { get { return m_SharedInstanceData.AsReadOnly(); } } public NativeArray aliveInstances { get { return m_InstanceData.instances.GetSubArray(0, m_InstanceData.instancesLength); } } @@ -49,10 +52,13 @@ namespace UnityEngine.Rendering m_InstanceAllocators = new InstanceAllocators(); m_SharedInstanceData = new CPUSharedInstanceData(); m_InstanceData = new CPUInstanceData(); + m_PerCameraInstanceData = new CPUPerCameraInstanceData(); m_InstanceAllocators.Initialize(); m_SharedInstanceData.Initialize(maxInstances); m_InstanceData.Initialize(maxInstances); + m_PerCameraInstanceData.Initialize(maxInstances); + Assert.IsTrue(m_PerCameraInstanceData.instancesCapacity == m_InstanceData.instancesCapacity); m_RendererGroupInstanceMultiHash = new NativeParallelMultiHashMap(maxInstances, Allocator.Persistent); @@ -78,6 +84,7 @@ namespace UnityEngine.Rendering m_InstanceAllocators.Dispose(); m_SharedInstanceData.Dispose(); m_InstanceData.Dispose(); + m_PerCameraInstanceData.Dispose(); m_RendererGroupInstanceMultiHash.Dispose(); @@ -473,22 +480,24 @@ namespace UnityEngine.Rendering } m_InstanceData.EnsureFreeInstances(newInstancesCount); + m_PerCameraInstanceData.Grow(m_InstanceData.instancesCapacity); + Assert.IsTrue(m_InstanceData.instancesCapacity == m_PerCameraInstanceData.instancesCapacity); m_SharedInstanceData.EnsureFreeInstances(newSharedInstancesCount); 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); + ref m_PerCameraInstanceData, ref m_SharedInstanceData, ref instances, ref m_RendererGroupInstanceMultiHash); } public void FreeRendererGroupInstances(NativeArray rendererGroupsID) { InstanceDataSystemBurst.FreeRendererGroupInstances(rendererGroupsID.AsReadOnly(), ref m_InstanceAllocators, ref m_InstanceData, - ref m_SharedInstanceData, ref m_RendererGroupInstanceMultiHash); + ref m_PerCameraInstanceData, ref m_SharedInstanceData, ref m_RendererGroupInstanceMultiHash); } public void FreeInstances(NativeArray instances) { - InstanceDataSystemBurst.FreeInstances(instances.AsReadOnly(), ref m_InstanceAllocators, ref m_InstanceData, + InstanceDataSystemBurst.FreeInstances(instances.AsReadOnly(), ref m_InstanceAllocators, ref m_InstanceData, ref m_PerCameraInstanceData, ref m_SharedInstanceData, ref m_RendererGroupInstanceMultiHash); } @@ -515,7 +524,8 @@ namespace UnityEngine.Rendering rendererData = rendererData, lodGroupDataMap = lodGroupDataMap, instanceData = m_InstanceData, - sharedInstanceData = m_SharedInstanceData + sharedInstanceData = m_SharedInstanceData, + perCameraInstanceData = m_PerCameraInstanceData }.Schedule(rendererData.rendererGroupID.Length, UpdateRendererInstancesJob.k_BatchSize); } @@ -813,5 +823,15 @@ namespace UnityEngine.Rendering public static readonly int _WindParamAddressArray = Shader.PropertyToID("_WindParamAddressArray"); public static readonly int _WindHistoryParamAddressArray = Shader.PropertyToID("_WindHistoryParamAddressArray"); } + + public void DeallocatePerCameraInstanceData(NativeArray cameraIDs) + { + m_PerCameraInstanceData.DeallocateCameras(cameraIDs); + } + + public void AllocatePerCameraInstanceData(NativeArray cameraIDs) + { + m_PerCameraInstanceData.AllocateCameras(cameraIDs); + } } } 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 index 986472f5..2f62c89a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystemBurst.cs @@ -10,7 +10,7 @@ namespace UnityEngine.Rendering [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 CPUPerCameraInstanceData perCameraInstanceData, ref CPUSharedInstanceData sharedInstanceData, ref NativeArray instances, ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) { for (int i = 0; i < rendererGroupIDs.Length; ++i) @@ -55,7 +55,7 @@ namespace UnityEngine.Rendering { var idx = instanceData.InstanceToIndex(instance); instanceData.Remove(instance); - + perCameraInstanceData.Remove(idx); instanceAllocators.FreeInstance(instance); rendererGroupInstanceMultiHash.Remove(it); @@ -91,6 +91,8 @@ namespace UnityEngine.Rendering newInstance = instanceAllocators.AllocateInstance(InstanceType.SpeedTree); instanceData.AddNoGrow(newInstance); + perCameraInstanceData.IncreaseInstanceCount(); + Assert.IsTrue(instanceData.instancesLength == perCameraInstanceData.instancesLength); int index = instanceData.InstanceToIndex(newInstance); instanceData.sharedInstances[index] = sharedInstance; instanceData.movedInCurrentFrameBits.Set(index, false); @@ -111,7 +113,7 @@ namespace UnityEngine.Rendering [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) + ref CPUPerCameraInstanceData perCameraInstanceData, ref CPUSharedInstanceData sharedInstanceData, ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) { foreach (var rendererGroupID in rendererGroupsID) { @@ -135,6 +137,7 @@ namespace UnityEngine.Rendering var idx = instanceData.InstanceToIndex(instance); instanceData.Remove(instance); + perCameraInstanceData.Remove(idx); instanceAllocators.FreeInstance(instance); success = rendererGroupInstanceMultiHash.TryGetNextValue(out instance, ref it); @@ -147,7 +150,7 @@ namespace UnityEngine.Rendering [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) + ref CPUPerCameraInstanceData perCameraInstanceData, ref CPUSharedInstanceData sharedInstanceData, ref NativeParallelMultiHashMap rendererGroupInstanceMultiHash) { foreach (var instance in instances) { @@ -171,8 +174,9 @@ namespace UnityEngine.Rendering sharedInstanceData.Remove(sharedInstance); instanceAllocators.FreeSharedInstance(sharedInstance); } - + var idx = instanceData.InstanceToIndex(instance); instanceData.Remove(instance); + perCameraInstanceData.Remove(idx); instanceAllocators.FreeInstance(instance); //@ This will have quadratic cost. Optimize later. 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 b9e47a3b..33e07168 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupDataPool.cs @@ -65,14 +65,14 @@ namespace UnityEngine.Rendering { float lodHeight = lodGroup->screenRelativeTransitionHeights[i]; - var lodDist = LODGroupRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize); + var lodDist = LODRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize); lodGroupTransformResult->sqrDistances[i] = lodDist * lodDist; if (supportDitheringCrossFade && !lodGroupTransformResult->percentageFlags[i]) { float prevLODHeight = i != 0 ? lodGroup->screenRelativeTransitionHeights[i - 1] : 1.0f; float transitionHeight = lodHeight + lodGroup->fadeTransitionWidth[i] * (prevLODHeight - lodHeight); - var transitionDistance = lodDist - LODGroupRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize); + var transitionDistance = lodDist - LODRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize); transitionDistance = Mathf.Max(0.0f, transitionDistance); lodGroupTransformResult->transitionDistances[i] = transitionDistance; } @@ -146,7 +146,7 @@ namespace UnityEngine.Rendering { var lodIndex = lodOffset + i; var lodHeight = inputData.lodScreenRelativeTransitionHeight[lodIndex]; - var lodDist = LODGroupRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize); + var lodDist = LODRenderingUtils.CalculateLODDistance(lodHeight, worldSpaceSize); lodGroupData->screenRelativeTransitionHeights[i] = lodHeight; lodGroupData->fadeTransitionWidth[i] = 0.0f; @@ -163,7 +163,7 @@ namespace UnityEngine.Rendering var fadeTransitionWidth = inputData.lodFadeTransitionWidth[lodIndex]; var prevLODHeight = i != 0 ? inputData.lodScreenRelativeTransitionHeight[lodIndex - 1] : 1.0f; var transitionHeight = lodHeight + fadeTransitionWidth * (prevLODHeight - lodHeight); - var transitionDistance = lodDist - LODGroupRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize); + var transitionDistance = lodDist - LODRenderingUtils.CalculateLODDistance(transitionHeight, worldSpaceSize); transitionDistance = Mathf.Max(0.0f, transitionDistance); lodGroupData->fadeTransitionWidth[i] = fadeTransitionWidth; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupRenderingUtils.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODRenderingUtils.cs similarity index 69% rename from Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupRenderingUtils.cs rename to Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODRenderingUtils.cs index d68bf0ba..8043ba9d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupRenderingUtils.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODRenderingUtils.cs @@ -5,30 +5,30 @@ using UnityEngine; namespace UnityEngine.Rendering { - // All this is just a copy of C++ LODGroupManager code. - internal static class LODGroupRenderingUtils + // Based on C++ LODGroupManager code. + internal static class LODRenderingUtils { public static float CalculateFOVHalfAngle(float fieldOfView) { return Mathf.Tan(Mathf.Deg2Rad * fieldOfView * 0.5f); } - public static float CalculateScreenRelativeMetric(LODParameters lodParams, float lodBias) - { - float screenRelativeMetric; - if (lodParams.isOrthographic) - { - screenRelativeMetric = 2.0F * lodParams.orthoSize; - } - else - { - // Half angle at 90 degrees is 1.0 (So we skip halfAngle / 1.0 calculation) - float halfAngle = CalculateFOVHalfAngle(lodParams.fieldOfView); - screenRelativeMetric = 2.0f * halfAngle; - } + public static float CalculateScreenRelativeMetricNoBias(LODParameters lodParams) + { + if (lodParams.isOrthographic) + { + return 2.0F * lodParams.orthoSize; + } + + // Half angle at 90 degrees is 1.0 (So we skip halfAngle / 1.0 calculation) + float halfAngle = CalculateFOVHalfAngle(lodParams.fieldOfView); + return 2.0f * halfAngle; + } - return screenRelativeMetric / lodBias; - } + public static float CalculateMeshLodConstant(LODParameters lodParams, float screenRelativeMetric, float meshLodThreshold) + { + return meshLodThreshold * screenRelativeMetric / lodParams.cameraPixelHeight; + } public static float CalculatePerspectiveDistance(Vector3 objPosition, Vector3 camPosition, float sqrScreenRelativeMetric) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupRenderingUtils.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODRenderingUtils.cs.meta similarity index 100% rename from Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODGroupRenderingUtils.cs.meta rename to Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/LODRenderingUtils.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/RenderersBatchersContext.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/RenderersBatchersContext.cs index 49e387d8..d223ce42 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/RenderersBatchersContext.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/RenderersBatchersContext.cs @@ -38,12 +38,14 @@ namespace UnityEngine.Rendering public NativeList lodGroupCullingData { get { return m_LODGroupDataPool.lodGroupCullingData; } } public int instanceDataBufferVersion { get { return m_InstanceDataBuffer.version; } } public int instanceDataBufferLayoutVersion { get { return m_InstanceDataBuffer.layoutVersion; } } - public int crossfadedRendererCount { get { return m_LODGroupDataPool.crossfadedRendererCount; } } public SphericalHarmonicsL2 cachedAmbientProbe { get { return m_CachedAmbientProbe; } } public bool hasBoundingSpheres { get { return m_InstanceDataSystem.hasBoundingSpheres; } } + public int cameraCount { get { return m_InstanceDataSystem.cameraCount; } } public CPUInstanceData.ReadOnly instanceData { get { return m_InstanceDataSystem.instanceData; } } public CPUSharedInstanceData.ReadOnly sharedInstanceData { get { return m_InstanceDataSystem.sharedInstanceData; } } + + public CPUPerCameraInstanceData perCameraInstanceData { get { return m_InstanceDataSystem.perCameraInstanceData; } } public GPUInstanceDataBuffer.ReadOnly instanceDataBuffer { get { return m_InstanceDataBuffer.AsReadOnly(); } } public NativeArray aliveInstances { get { return m_InstanceDataSystem.aliveInstances; } } @@ -386,6 +388,16 @@ namespace UnityEngine.Rendering m_OcclusionCullingCommon.UpdateOccluderStats(m_DebugStats); } + public void FreePerCameraInstanceData(NativeArray cameraIDs) + { + m_InstanceDataSystem.DeallocatePerCameraInstanceData(cameraIDs); + } + + public void UpdateCameras(NativeArray cameraIDs) + { + m_InstanceDataSystem.AllocatePerCameraInstanceData(cameraIDs); + } + #if UNITY_EDITOR public void UpdateSelectedInstances(NativeArray instances) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.cs index 7bc10677..503baeee 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.cs @@ -8,7 +8,7 @@ namespace UnityEngine.Rendering [CoreRPHelpURL("probevolumes-adjustment-volume-component-reference", "com.unity.render-pipelines.high-definition")] [ExecuteAlways] [AddComponentMenu("Rendering/Probe Adjustment Volume")] - public class ProbeAdjustmentVolume : MonoBehaviour, ISerializationCallbackReceiver + public partial class ProbeAdjustmentVolume : MonoBehaviour, ISerializationCallbackReceiver { /// The type of shape that an adjustment volume can take. public enum Shape @@ -234,9 +234,7 @@ namespace UnityEngine.Rendering } #endif - // Migration related stuff - enum Version { Initial, @@ -248,31 +246,6 @@ namespace UnityEngine.Rendering [SerializeField] Version version = Version.Count; - /// Whether to invalidate all probes falling within this volume. - [Obsolete("Use mode")] - public bool invalidateProbes = false; - /// Whether to use a custom threshold for dilation for probes falling withing this volume. - [Obsolete("Use mode")] - public bool overrideDilationThreshold = false; - - void Awake() - { - if (version == Version.Count) - return; - - if (version == Version.Initial) - { -#pragma warning disable 618 // Type or member is obsolete - if (invalidateProbes) - mode = Mode.InvalidateProbes; - else if (overrideDilationThreshold) - mode = Mode.OverrideValidityThreshold; -#pragma warning restore 618 - - version++; - } - } - // This piece of code is needed because some objects could have been created before existence of Version enum /// OnBeforeSerialize needed to handle migration before the versioning system was in place. void ISerializationCallbackReceiver.OnBeforeSerialize() @@ -286,6 +259,18 @@ namespace UnityEngine.Rendering { if (version == Version.Count) // deserializing and object without version version = Version.Initial; // reset to run the migration + + if (version < Version.Mode) + { +#pragma warning disable 618 // Type or member is obsolete + if (invalidateProbes) + mode = Mode.InvalidateProbes; + else if (overrideDilationThreshold) + mode = Mode.OverrideValidityThreshold; +#pragma warning restore 618 + + version = Version.Mode; + } } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs new file mode 100644 index 00000000..bca11c2e --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs @@ -0,0 +1,13 @@ +using System; + +namespace UnityEngine.Rendering +{ + public partial class ProbeAdjustmentVolume + { + /// Whether to invalidate all probes falling within this volume. + [Obsolete("This field is only kept for migration purpose. Use mode instead. #from(2023.1)")] public bool invalidateProbes = false; + + /// Whether to use a custom threshold for dilation for probes falling withing this volume. + [Obsolete("This field is only kept for migration purpose. Use mode instead. #from(2023.1)")] public bool overrideDilationThreshold = false; + } +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs.meta new file mode 100644 index 00000000..a602b5af --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeAdjustmentVolume.deprecated.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a91edae7e71f48b9880e1bda95128cfd +timeCreated: 1739986118 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Binding.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Binding.cs index 352f617c..0340eca5 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Binding.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Binding.cs @@ -137,8 +137,8 @@ namespace UnityEngine.Rendering parameters.skyOcclusionIntensity = skyOcclusion ? probeVolumeOptions.skyOcclusionIntensityMultiplier.value : 0.0f; parameters.skyOcclusionShadingDirection = skyOcclusion && skyOcclusionShadingDirection; - parameters.regionCount = m_CurrentBakingSet.bakedMaskCount; - parameters.regionLayerMasks = supportRenderingLayers ? m_CurrentBakingSet.bakedLayerMasks : 0xFFFFFFFF; + parameters.regionCount = m_CurrentBakingSet != null ? m_CurrentBakingSet.bakedMaskCount : 0; + parameters.regionLayerMasks = (supportRenderingLayers && m_CurrentBakingSet != null) ? m_CurrentBakingSet.bakedLayerMasks : 0xFFFFFFFF; parameters.worldOffset = probeVolumeOptions.worldOffset.value; UpdateConstantBuffer(cmd, parameters); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs index f0474d66..37b84ecd 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs @@ -566,7 +566,11 @@ namespace UnityEngine.Rendering displayName = "Max Subdivisions Displayed", tooltip = "The highest (most dense) probe subdivision level displayed in the debug view.", getter = () => probeVolumeDebug.maxSubdivToVisualize, - setter = (v) => probeVolumeDebug.maxSubdivToVisualize = Mathf.Max(0, Mathf.Min(v, GetMaxSubdivision() - 1)), + setter = (v) => + { + // If no baked data, force to set the value as kMaxSubdivisionLevels for UX. + probeVolumeDebug.maxSubdivToVisualize = GetMaxSubdivision() == 0 ? ProbeBrickIndex.kMaxSubdivisionLevels : Mathf.Max(0, Mathf.Min(v, GetMaxSubdivision() - 1)); + }, min = () => 0, max = () => Mathf.Max(0, GetMaxSubdivision() - 1), }); @@ -1084,6 +1088,240 @@ namespace UnityEngine.Rendering realtimeSubdivisionInfo.Clear(); } + static void DecompressSH(ref SphericalHarmonicsL2 shv) + { + for (int rgb = 0; rgb < 3; ++rgb) + { + var l0 = shv[rgb, 0]; + + // See CompressSH + float l1scale = 2.0f; + float l2scale = 3.5777088f; + + // L_1^m + shv[rgb, 1] = (shv[rgb, 1] - 0.5f) * (l0 * l1scale * 2.0f); + shv[rgb, 2] = (shv[rgb, 2] - 0.5f) * (l0 * l1scale * 2.0f); + shv[rgb, 3] = (shv[rgb, 3] - 0.5f) * (l0 * l1scale * 2.0f); + + // L_2^-2 + shv[rgb, 4] = (shv[rgb, 4] - 0.5f) * (l0 * l2scale * 2.0f); + shv[rgb, 5] = (shv[rgb, 5] - 0.5f) * (l0 * l2scale * 2.0f); + shv[rgb, 6] = (shv[rgb, 6] - 0.5f) * (l0 * l2scale * 2.0f); + shv[rgb, 7] = (shv[rgb, 7] - 0.5f) * (l0 * l2scale * 2.0f); + shv[rgb, 8] = (shv[rgb, 8] - 0.5f) * (l0 * l2scale * 2.0f); + } + } + + internal static Vector3 DecodeSkyShadingDirection(uint directionIndex) + { + var precomputedDirections = ProbeVolumeConstantRuntimeResources.GetSkySamplingDirections(); + Debug.Assert(directionIndex < precomputedDirections.Length + 1); + return directionIndex == precomputedDirections.Length ? new Vector3(0.0f, 0.0f, 0.0f) : precomputedDirections[directionIndex]; + } + + internal bool GetFlattenedProbeData( + string scenario, + out Vector3[] positions, + out SphericalHarmonicsL2[] irradiance, + out float[] validity, + out Vector4[] occlusion, + out Vector4[] skyOcclusion, + out Vector3[] skyOcclusionDirections, + out Vector3[] virtualOffset) + { + positions = null; + irradiance = null; + validity = null; + occlusion = null; + skyOcclusion = null; + skyOcclusionDirections = null; + virtualOffset = null; + + var positionsList = new List(); + var irradianceList = new List(); + var validityList = new List(); + var occlusionList = new List(); + var skyOcclusionList = new List(); + var skyOcclusionDirectionList = new List(); + var virtualOffsetList = new List(); + + foreach (var cell in cells.Values) + { + if (HasActiveStreamingRequest(cell)) + return false; + + if (!cell.data.bricks.IsCreated || cell.data.bricks.Length == 0 || + !cell.data.probePositions.IsCreated || !cell.loaded) + return false; + + if (!cell.data.scenarios.TryGetValue(scenario, out var scenarioData)) + return false; + + var chunks = cell.poolInfo.chunkList; + var chunkSizeInProbes = ProbeBrickPool.GetChunkSizeInProbeCount(); + var loc = ProbeBrickPool.ProbeCountToDataLocSize(chunkSizeInProbes); + + int brickCount = cell.desc.probeCount / ProbeBrickPool.kBrickProbeCountTotal; + + int bx = 0, by = 0, bz = 0; + for (int brickIndex = 0; brickIndex < brickCount; ++brickIndex) + { + Debug.Assert(bz < loc.z); + + int chunkIndex = brickIndex / ProbeBrickPool.GetChunkSizeInBrickCount(); + var chunk = chunks[chunkIndex]; + Vector3Int brickStart = new Vector3Int(chunk.x + bx, chunk.y + by, chunk.z + bz); + + for (int z = 0; z < ProbeBrickPool.kBrickProbeCountPerDim; ++z) + { + for (int y = 0; y < ProbeBrickPool.kBrickProbeCountPerDim; ++y) + { + for (int x = 0; x < ProbeBrickPool.kBrickProbeCountPerDim; ++x) + { + Vector3Int texelLoc = new Vector3Int(brickStart.x + x, brickStart.y + y, brickStart.z + z); + + int probeFlatIndex = chunkIndex * chunkSizeInProbes + (bx + x) + loc.x * ((by + y) + loc.y * (bz + z)); + var position = cell.data.probePositions[probeFlatIndex] - ProbeOffset(); // Offset is applied in shader + + positionsList.Add(position); + validityList.Add(cell.data.validity[probeFlatIndex]); + var occlusionOffset = probeFlatIndex * 4; + float occlusionValue0 = scenarioData.probeOcclusion[occlusionOffset] / 255.0f; + float occlusionValue1 = scenarioData.probeOcclusion[occlusionOffset+1] / 255.0f; + float occlusionValue2 = scenarioData.probeOcclusion[occlusionOffset+2] / 255.0f; + float occlusionValue3 = scenarioData.probeOcclusion[occlusionOffset+3] / 255.0f; + occlusionList.Add(new Vector4(occlusionValue0, occlusionValue1, occlusionValue2, occlusionValue3)); + + if (cell.data.skyOcclusionDataL0L1.Length > 0) + { + // sky occlusion L0/L1 SH + var skyOccSH_dc = Mathf.HalfToFloat(cell.data.skyOcclusionDataL0L1[probeFlatIndex * 4]); + var skyOccSH_x = Mathf.HalfToFloat(cell.data.skyOcclusionDataL0L1[probeFlatIndex * 4 + 1]); + var skyOccSH_y = Mathf.HalfToFloat(cell.data.skyOcclusionDataL0L1[probeFlatIndex * 4 + 2]); + var skyOccSH_z = Mathf.HalfToFloat(cell.data.skyOcclusionDataL0L1[probeFlatIndex * 4 + 3]); + skyOcclusionList.Add(new Vector4(skyOccSH_dc, skyOccSH_x, skyOccSH_y, skyOccSH_z)); + } + + if (cell.data.skyShadingDirectionIndices.Length > 0) + { + // sky occlusion direction + var skyOccSDI = cell.data.skyShadingDirectionIndices[probeFlatIndex]; + var skyOcclusionDirection = DecodeSkyShadingDirection(skyOccSDI); + skyOcclusionDirectionList.Add(skyOcclusionDirection); + } + + if (cell.data.offsetVectors.Length > 0) + { + var offsetValue = cell.data.offsetVectors[probeFlatIndex]; + virtualOffsetList.Add(offsetValue); + } + + Vector4 L0_L1Rx = Vector4.zero; + Vector4 L1G_L1Ry = Vector4.zero; + Vector4 L1B_L1Rz = Vector4.zero; + Vector4 L2_R = Vector4.zero; + Vector4 L2_G = Vector4.zero; + Vector4 L2_B = Vector4.zero; + Vector4 L2_C = Vector4.zero; + for (int channel = 0; channel < 4; channel++) + { + L0_L1Rx[channel] = Mathf.HalfToFloat(scenarioData.shL0L1RxData[probeFlatIndex * 4 + channel]); + L1G_L1Ry[channel] = scenarioData.shL1GL1RyData[probeFlatIndex * 4 + channel] / 255.0f; + L1B_L1Rz[channel] = scenarioData.shL1BL1RzData[probeFlatIndex * 4 + channel] / 255.0f; + + if (ProbeReferenceVolume.instance.shBands == ProbeVolumeSHBands.SphericalHarmonicsL2) + { + L2_R[channel] = scenarioData.shL2Data_0[probeFlatIndex * 4 + channel] / 255.0f; + L2_G[channel] = scenarioData.shL2Data_1[probeFlatIndex * 4 + channel] / 255.0f; + L2_B[channel] = scenarioData.shL2Data_2[probeFlatIndex * 4 + channel] / 255.0f; + L2_C[channel] = scenarioData.shL2Data_3[probeFlatIndex * 4 + channel] / 255.0f; + } + } + + Vector3 L0 = new Vector3(L0_L1Rx.x, L0_L1Rx.y, L0_L1Rx.z); + // Note: yzx swizzle happening here + Vector3 L1_R = new Vector3(L1G_L1Ry.w, L1B_L1Rz.w, L0_L1Rx.w); + Vector3 L1_G = new Vector3(L1G_L1Ry.y, L1G_L1Ry.z, L1G_L1Ry.x); + Vector3 L1_B = new Vector3(L1B_L1Rz.y, L1B_L1Rz.z, L1B_L1Rz.x); + + SphericalHarmonicsL2 sh = new SphericalHarmonicsL2(); + // L0, L1 + for (int i = 0; i < 3; i++) + { + sh[i, 0] = L0[i]; + + sh[0, i + 1] = L1_R[i]; + sh[1, i + 1] = L1_G[i]; + sh[2, i + 1] = L1_B[i]; + } + // L2 + { + sh[0, 4] = L2_R.x; + sh[0, 5] = L2_R.y; + sh[0, 6] = L2_R.z; + sh[0, 7] = L2_R.w; + sh[0, 8] = L2_C.x; + + sh[1, 4] = L2_G.x; + sh[1, 5] = L2_G.y; + sh[1, 6] = L2_G.z; + sh[1, 7] = L2_G.w; + sh[1, 8] = L2_C.y; + + sh[2, 4] = L2_B.x; + sh[2, 5] = L2_B.y; + sh[2, 6] = L2_B.z; + sh[2, 7] = L2_B.w; + sh[2, 8] = L2_C.z; + } + DecompressSH(ref sh); + // Decompressing zero'd L2 data will create bogus values on the L2 coefficients. + if (ProbeReferenceVolume.instance.shBands != ProbeVolumeSHBands.SphericalHarmonicsL2) + { + for (int i = 0; i < 5; i++) + { + sh[0, i + 4] = 0; + sh[1, i + 4] = 0; + sh[2, i + 4] = 0; + } + } + + irradianceList.Add(sh); + } + } + } + + bx += ProbeBrickPool.kBrickProbeCountPerDim; + if (bx >= loc.x) + { + bx = 0; + by += ProbeBrickPool.kBrickProbeCountPerDim; + if (by >= loc.y) + { + by = 0; + bz += ProbeBrickPool.kBrickProbeCountPerDim; + if (bz >= loc.z) + { + bx = 0; + by = 0; + bz = 0; + } + } + } + } + } + + positions = positionsList.ToArray(); + irradiance = irradianceList.ToArray(); + validity = validityList.ToArray(); + occlusion = occlusionList.ToArray(); + skyOcclusion = skyOcclusionList.ToArray(); + skyOcclusionDirections = skyOcclusionDirectionList.ToArray(); + virtualOffset = virtualOffsetList.ToArray(); + + return true; + } + CellInstancedDebugProbes CreateInstancedProbes(Cell cell) { if (cell.debugProbes != null) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.ReflProbeNormalization.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.ReflProbeNormalization.cs index 97fbeb60..34a74a33 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.ReflProbeNormalization.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.ReflProbeNormalization.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Unity.Collections; #if UNITY_EDITOR @@ -25,6 +26,7 @@ namespace UnityEngine.Rendering public static AdditionalGIBakeRequestsManager instance { get { return s_Instance; } } const float kInvalidSH = 1f; + const float kInvalidValidity = 1f; const float kValidSHThresh = 0.33f; private static Dictionary m_SHCoefficients = new Dictionary(); @@ -64,6 +66,7 @@ namespace UnityEngine.Rendering /// The output SH coefficients that have been computed. /// The position for which the computed SH coefficients are valid. /// Whether the request for light probe rendering has been fulfilled and sh is valid. + [Obsolete("Use RetrieveProbe instead.", false)] public bool RetrieveProbeSH(int probeInstanceID, out SphericalHarmonicsL2 sh, out Vector3 pos) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) @@ -78,6 +81,32 @@ namespace UnityEngine.Rendering return false; } + /// + /// Retrieve the result of a capture request, it will return false if the request ID is invalid. + /// + /// The instance ID of the probe doing the request. + /// The position for which the computed SH coefficients are valid. + /// The output SH coefficients that have been computed. + /// The output validity that has been computed. + /// True if the request ID is valid. + public bool RetrieveProbe(EntityId probeInstanceID, out Vector3 pos, out SphericalHarmonicsL2 sh, out float validity) + { + if (m_SHCoefficients.ContainsKey(probeInstanceID)) + { + sh = m_SHCoefficients[probeInstanceID]; + pos = m_RequestPositions[probeInstanceID]; + validity = m_SHValidity[probeInstanceID]; + + return true; + } + + sh = new SphericalHarmonicsL2(); + pos = Vector3.negativeInfinity; + validity = float.NegativeInfinity; + + return false; + } + static internal bool GetPositionForRequest(int probeInstanceID, out Vector3 pos) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) 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 6ece01ff..b6cea371 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 @@ -726,8 +726,19 @@ namespace UnityEngine.Rendering // Information of the probe volume scenes that is being loaded (if one is pending) List m_ActiveScenes = new List(); - ProbeVolumeBakingSet m_CurrentBakingSet = null; - ProbeVolumeBakingSet m_LazyBakingSet = null; + ProbeVolumeBakingSetWeakReference m_CurrentBakingSetReference = new(); + ProbeVolumeBakingSet m_CurrentBakingSet + { + get => m_CurrentBakingSetReference.Get(); + set => m_CurrentBakingSetReference.Set(value); + } + + ProbeVolumeBakingSetWeakReference m_LazyBakingSetReference = new(); + ProbeVolumeBakingSet m_LazyBakingSet + { + get => m_LazyBakingSetReference.Get(); + set => m_LazyBakingSetReference.Set(value); + } bool m_NeedLoadAsset = false; bool m_ProbeReferenceVolumeInit = false; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.Editor.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.Editor.cs index 3b52d8fa..249a1ea2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.Editor.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.Editor.cs @@ -22,7 +22,7 @@ namespace UnityEngine.Rendering [SerializeField] SerializedDictionary m_SceneBakeData = new(); - internal static Dictionary sceneToBakingSet = new Dictionary(); + internal static Dictionary sceneToBakingSet = new Dictionary(); /// /// Tries to add a scene to the baking set. @@ -42,7 +42,7 @@ namespace UnityEngine.Rendering { m_SceneGUIDs.Add(guid); m_SceneBakeData.Add(guid, bakeData != null ? bakeData : new SceneBakeData()); - sceneToBakingSet[guid] = this; + sceneToBakingSet[guid] = new ProbeVolumeBakingSetWeakReference(this); EditorUtility.SetDirty(this); } @@ -65,7 +65,7 @@ namespace UnityEngine.Rendering var previousSceneGUID = m_SceneGUIDs[index]; m_SceneGUIDs[index] = guid; sceneToBakingSet.Remove(previousSceneGUID); - sceneToBakingSet[guid] = this; + sceneToBakingSet[guid] = new ProbeVolumeBakingSetWeakReference(this); m_SceneBakeData.Add(guid, bakeData != null ? bakeData : new SceneBakeData()); EditorUtility.SetDirty(this); @@ -291,26 +291,34 @@ namespace UnityEngine.Rendering internal static void SyncBakingSets() { - sceneToBakingSet = new Dictionary(); + sceneToBakingSet = new Dictionary(); - var setGUIDs = AssetDatabase.FindAssets("t:" + typeof(ProbeVolumeBakingSet).Name); + var setGUIDs = AssetDatabase.FindAssets("t:" + nameof(ProbeVolumeBakingSet)); foreach (var setGUID in setGUIDs) { - var set = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(setGUID)); + string bakingSetPath = AssetDatabase.GUIDToAssetPath(setGUID); + bool alreadyLoaded = AssetDatabase.IsMainAssetAtPathLoaded(bakingSetPath); + + var set = AssetDatabase.LoadAssetAtPath(bakingSetPath); if (set != null) { // We need to call Migrate here because of Version.RemoveProbeVolumeSceneData step. // This step needs the obsolete ProbeVolumeSceneData to be initialized first which can happen out of order. Here we now it's ok. set.Migrate(); + var reference = new ProbeVolumeBakingSetWeakReference(set); foreach (var guid in set.sceneGUIDs) - sceneToBakingSet[guid] = set; + sceneToBakingSet[guid] = reference; + + // If the asset wasn't already in-memory, and we just loaded it into memory, free it, so we don't waste memory. + if (!alreadyLoaded) + reference.Unload(); } } } - internal static ProbeVolumeBakingSet GetBakingSetForScene(string sceneGUID) => sceneToBakingSet.GetValueOrDefault(sceneGUID, null); + internal static ProbeVolumeBakingSet GetBakingSetForScene(string sceneGUID) => sceneToBakingSet.GetValueOrDefault(sceneGUID, null)?.Get(); internal static ProbeVolumeBakingSet GetBakingSetForScene(Scene scene) => GetBakingSetForScene(scene.GetGUID()); internal void SetDefaults() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs new file mode 100644 index 00000000..5e4147db --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs @@ -0,0 +1,75 @@ +namespace UnityEngine.Rendering +{ + // Q: What is this? + // A: A utility class for storing a reference to a ProbeVolumeBakingSet, without forcing the object to be loaded in-memory. + + // Q: Why do we need this? + // A: APV uses a lot of global state, and we aren't always good with cleaning it up. Unity's serialization layer will automatically + // load referenced assets into memory, recursively. Some of the assets referenced by ProbeVolumeBakingSet can get very large, on + // the order of several gigabytes. A lingering global reference to a ProbeVolumeBakingSet can keep these assets in memory indefinitely, + // preventing them from being garbage collected. By using a weak reference, we prevent this - ProbeVolumeBakingSet can be freely + // garbage collected. Whenever we actually need to access it, we load it on-demand, if it isn't already in memory. + + internal class ProbeVolumeBakingSetWeakReference + { + public int m_InstanceID; + + public ProbeVolumeBakingSetWeakReference(ProbeVolumeBakingSet bakingSet) + { + Set(bakingSet); + } + + public ProbeVolumeBakingSetWeakReference() + { + m_InstanceID = 0; + } + + // Change which baking set the references points to. + public void Set(ProbeVolumeBakingSet bakingSet) + { + if (bakingSet == null) + m_InstanceID = 0; + else + m_InstanceID = bakingSet.GetInstanceID(); + } + + // Get the referenced baking set, loading it into memory if necessary. + public ProbeVolumeBakingSet Get() + { + return Resources.InstanceIDToObject(m_InstanceID) as ProbeVolumeBakingSet; + } + + // Is the referenced baking set in memory? + public bool IsLoaded() + { + return Resources.InstanceIDIsValid(m_InstanceID); + } + + // Force the referenced baking set to be unloaded from memory. + // Calling Get() after Unload() will re-load the baking set into memory. + public void Unload() + { + if (!IsLoaded()) + return; + + var bakingSet = Get(); + + // These assets would get garbage collected, but we clean them up immediately to free memory earlier. + // Only do this in editor, where the assets are never needed, so we don't unload assets that may still be in use. + #if UNITY_EDITOR + Resources.UnloadAsset(bakingSet.cellBricksDataAsset?.asset); + Resources.UnloadAsset(bakingSet.cellSharedDataAsset?.asset); + Resources.UnloadAsset(bakingSet.cellSupportDataAsset?.asset); + foreach (var scenario in bakingSet.scenarios) + { + Resources.UnloadAsset(scenario.Value.cellDataAsset?.asset); + Resources.UnloadAsset(scenario.Value.cellOptionalDataAsset?.asset); + Resources.UnloadAsset(scenario.Value.cellProbeOcclusionDataAsset?.asset); + } + #endif + + // Unload the baking set itself. + Resources.UnloadAsset(bakingSet); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs.meta new file mode 100644 index 00000000..4e4d247d --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ec6eec0d49474f845b4288cb1dc2525a \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute index 3376ed34..20b28b21 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #pragma kernel BlendScenarios diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute index f95fd582..d80bf698 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataCommon.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute index 881eeac7..5fbf608d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataCommon.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs index 20ecdb6b..622cc354 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs @@ -583,7 +583,7 @@ namespace UnityEngine.Rendering /// } /// /// - static public float ShapeAttenuationAreaTubeLight(Vector3 lightPositionWS, Vector3 lightSide, float lightWidth, Camera cam) + public static float ShapeAttenuationAreaTubeLight(Vector3 lightPositionWS, Vector3 lightSide, float lightWidth, Camera cam) { // Ref: https://hal.archives-ouvertes.fr/hal-02155101/document // Listing 1.6. Analytic line-diffuse integration. @@ -597,15 +597,16 @@ namespace UnityEngine.Rendering return l * l / (d * (d * d + l * l)); } - Vector3 p1Global = lightPositionWS + lightSide * lightWidth * 0.5f; - Vector3 p2Global = lightPositionWS - lightSide * lightWidth * 0.5f; - Vector3 p1Front = lightPositionWS + cam.transform.right * lightWidth * 0.5f; - Vector3 p2Front = lightPositionWS - cam.transform.right * lightWidth * 0.5f; + var cameraTransform = cam.transform; + Vector3 p1Global = lightPositionWS + 0.5f * lightWidth * lightSide; + Vector3 p2Global = lightPositionWS - 0.5f * lightWidth * lightSide; + Vector3 p1Front = lightPositionWS + 0.5f * lightWidth * cameraTransform.right; + Vector3 p2Front = lightPositionWS - 0.5f * lightWidth * cameraTransform.right; - Vector3 p1World = cam.transform.InverseTransformPoint(p1Global); - Vector3 p2World = cam.transform.InverseTransformPoint(p2Global); - Vector3 p1WorldFront = cam.transform.InverseTransformPoint(p1Front); - Vector3 p2WorldFront = cam.transform.InverseTransformPoint(p2Front); + Vector3 p1World = cameraTransform.InverseTransformPoint(p1Global); + Vector3 p2World = cameraTransform.InverseTransformPoint(p2Global); + Vector3 p1WorldFront = cameraTransform.InverseTransformPoint(p1Front); + Vector3 p2WorldFront = cameraTransform.InverseTransformPoint(p2Front); float DiffLineIntegral(Vector3 p1, Vector3 p2) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs index c1a42b35..578cf80a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs @@ -8,7 +8,7 @@ using Unity.Collections.LowLevel.Unsafe; namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { // Wrapper struct to allow storing strings in a DynamicArray which requires a type with a parameterless constructor - internal struct Name + internal readonly struct Name { public readonly string name; public readonly int utf8ByteCount; @@ -179,13 +179,12 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // not int the middle of lists Debug.Assert(listFirstIndex + numItems == fragmentData.Length); - fragmentData.Add(new PassFragmentData() - { - resource = access.textureHandle.handle, - accessFlags = access.flags, - mipLevel = access.mipLevel, - depthSlice = access.depthSlice, - }); + fragmentData.Add(new PassFragmentData( + access.textureHandle.handle, + access.flags, + access.mipLevel, + access.depthSlice + )); return true; } @@ -222,12 +221,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // not int the middle of lists Debug.Assert(listFirstIndex + numItems == randomAccessResourceData.Length); - randomAccessResourceData.Add(new PassRandomWriteData() - { - resource = h, - index = randomWriteSlotIndex, - preserveCounterValue = preserveCounterValue - }); + randomAccessResourceData.Add(new PassRandomWriteData(h, randomWriteSlotIndex, preserveCounterValue)); return true; } @@ -248,7 +242,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } // Helper to loop over native passes - public struct NativePassIterator + public ref struct NativePassIterator { readonly CompilerContextData m_Ctx; int m_Index; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs index ad71cfde..86824d15 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs @@ -60,7 +60,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } - public bool Initialize(RenderGraphResourceRegistry resources, List renderPasses, RenderGraphDebugParams debugParams, string debugName, bool useCompilationCaching, int graphHash, int frameIndex) + public bool Initialize(RenderGraphResourceRegistry resources, List renderPasses, RenderGraphDebugParams debugParams, string debugName, bool useCompilationCaching, + int graphHash, int frameIndex) { bool cached = false; if (!useCompilationCaching) @@ -117,7 +118,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler NRPRGComp_TryMergeNativePasses, NRPRGComp_FindResourceUsageRanges, NRPRGComp_DetectMemorylessResources, - NRPRGComp_ExecuteCreateResources, + NRPRGComp_ExecuteInitializeResources, NRPRGComp_ExecuteBeginRenderpassCommand, NRPRGComp_ExecuteDestroyResources, } @@ -150,8 +151,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (inputPass.type == RenderGraphPassType.Legacy) { throw new Exception("Pass '" + inputPass.name + "' is using the legacy rendergraph API." + - " You cannot use legacy passes with the native render pass compiler." + - " Please do not use AddPass on the rendergrpah but use one of the more specific pass types such as AddRasterRenderPass"); + " You cannot use legacy passes with the Native Render Pass Compiler." + + " The APIs that are compatible with the Native Render Pass Compiler are AddUnsafePass, AddComputePass and AddRasterRenderPass."); } #endif @@ -270,10 +271,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Mark this pass as writing to this version of the resource ctx.resources[resource].SetWritingPass(ctx, resource, passId); - ctx.outputData.Add(new PassOutputData - { - resource = resource, - }); + ctx.outputData.Add(new PassOutputData(resource)); ctxPass.numOutputs++; } @@ -287,10 +285,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Mark this pass as reading from this version of the resource ctx.resources[resource].RegisterReadingPass(ctx, resource, passId, ctxPass.numInputs); - ctx.inputData.Add(new PassInputData - { - resource = resource, - }); + ctx.inputData.Add(new PassInputData(resource)); ctxPass.numInputs++; } @@ -305,20 +300,14 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Mark this pass as reading from this version of the resource ctx.resources[resource].RegisterReadingPass(ctx, resource, passId, ctxPass.numInputs); - ctx.inputData.Add(new PassInputData - { - resource = resource, - }); + ctx.inputData.Add(new PassInputData(resource)); ctxPass.numInputs++; // Mark this pass as writing to this version of the resource ctx.resources[resource].SetWritingPass(ctx, resource, passId); - ctx.outputData.Add(new PassOutputData - { - resource = resource, - }); + ctx.outputData.Add(new PassOutputData(resource)); ctxPass.numOutputs++; } @@ -577,8 +566,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler var last = pointTo.latestVersionNumber; if (last == inputResource.version) { - var refC = pointTo.tag - 1;//Decrease refcount this pass is done using it - if (refC == 0)// We're the last pass done using it, this pass should destroy it. + var refC = pointTo.tag - 1; //Decrease refcount this pass is done using it + if (refC == 0) // We're the last pass done using it, this pass should destroy it. { pointTo.lastUsePassID = pass.passId; pass.AddLastUse(inputResource, ctx); @@ -655,6 +644,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler return true; } } + return false; } @@ -716,8 +706,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler internal static bool IsSameNativeSubPass(ref SubPassDescriptor a, ref SubPassDescriptor b) { if (a.flags != b.flags - || a.colorOutputs.Length != b.colorOutputs.Length - || a.inputs.Length != b.inputs.Length) + || a.colorOutputs.Length != b.colorOutputs.Length + || a.inputs.Length != b.inputs.Length) { return false; } @@ -741,10 +731,9 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler return true; } - - private void ExecuteCreateRessource(InternalRenderGraphContext rgContext, RenderGraphResourceRegistry resources, in PassData pass) + private void ExecuteInitializeResource(InternalRenderGraphContext rgContext, RenderGraphResourceRegistry resources, in PassData pass) { - using (new ProfilingScope(ProfilingSampler.Get(NativeCompilerProfileId.NRPRGComp_ExecuteCreateResources))) + using (new ProfilingScope(ProfilingSampler.Get(NativeCompilerProfileId.NRPRGComp_ExecuteInitializeResources))) { resources.forceManualClearOfResource = true; @@ -759,15 +748,23 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler foreach (ref readonly var res in subPass.FirstUsedResources(contextData)) { ref readonly var resInfo = ref contextData.UnversionedResourceData(res); - if (resInfo.isImported == false && resInfo.memoryLess == false) + if (!resInfo.memoryLess) { - bool usedAsFragmentThisPass = subPass.IsUsedAsFragment(res, contextData); + if (!resInfo.isImported) + { + bool usedAsFragmentThisPass = subPass.IsUsedAsFragment(res, contextData); - // This resource is read for the first time as a regular texture and not as a framebuffer attachment - // so we need to explicitly clear it, as loadAction.clear only works on framebuffer attachments - // TODO: Should this be a performance warning?? Maybe rare enough in practice? - resources.forceManualClearOfResource = !usedAsFragmentThisPass; - resources.CreatePooledResource(rgContext, res.iType, res.index); + // This resource is read for the first time as a regular texture and not as a framebuffer attachment + // so we need to explicitly clear it, as loadAction.clear only works on framebuffer attachments + // TODO: Should this be a performance warning?? Maybe rare enough in practice? + resources.forceManualClearOfResource = !usedAsFragmentThisPass; + resources.CreatePooledResource(rgContext, res.iType, res.index); + } + else // Imported resource + { + if (resInfo.clear) + resources.ClearResource(rgContext, res.iType, res.index); + } } } } @@ -779,10 +776,15 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler foreach (ref readonly var create in pass.FirstUsedResources(contextData)) { ref readonly var pointTo = ref contextData.UnversionedResourceData(create); - if (pointTo.isImported == false) + if (!pointTo.isImported) { resources.CreatePooledResource(rgContext, create.iType, create.index); } + else // Imported resource + { + if (pointTo.clear) + resources.ClearResource(rgContext, create.iType, create.index); + } } } @@ -790,7 +792,6 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } - void DetermineLoadStoreActions(ref NativePassData nativePass) { using (new ProfilingScope(ProfilingSampler.Get(NativeCompilerProfileId.NRPRGComp_PrepareNativePass))) @@ -801,13 +802,12 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Some passes don't do any rendering only state changes so just skip them // If these passes trigger any drawing the raster command buffer will warn users no render targets are set-up for their rendering if (nativePass.fragments.size <= 0) - { return; - } // Some sanity checks, these should not happen - Debug.Assert(firstGraphPass.mergeState == PassMergeState.Begin || firstGraphPass.mergeState == PassMergeState.None); - Debug.Assert(lastGraphPass.mergeState == PassMergeState.End || lastGraphPass.mergeState == PassMergeState.None); + Debug.Assert(firstGraphPass.mergeState is PassMergeState.Begin or PassMergeState.None); + Debug.Assert(lastGraphPass.mergeState is PassMergeState.End or PassMergeState.None); + ref readonly var fragmentList = ref nativePass.fragments; // determine load store actions @@ -818,28 +818,28 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { ref readonly var fragment = ref fragmentList[fragmentId]; - int idx = nativePass.attachments.Add(new NativePassAttachment()); - ref var currAttachment = ref nativePass.attachments[idx]; + // Default values + ResourceHandle handle = fragment.resource; + bool memoryless = false; + int mipLevel = fragment.mipLevel; + int depthSlice = fragment.depthSlice; + // Don't care by default + RenderBufferLoadAction loadAction = RenderBufferLoadAction.DontCare; + RenderBufferStoreAction storeAction = RenderBufferStoreAction.DontCare; #if UNITY_EDITOR nativePass.loadAudit.Add(new LoadAudit(LoadReason.FullyRewritten)); - ref var currLoadAudit = ref nativePass.loadAudit[idx]; + ref var currLoadAudit = ref nativePass.loadAudit[nativePass.loadAudit.size - 1]; // Get the last added element nativePass.storeAudit.Add(new StoreAudit(StoreReason.DiscardUnused)); - ref var currStoreAudit = ref nativePass.storeAudit[idx]; + ref var currStoreAudit = ref nativePass.storeAudit[nativePass.storeAudit.size - 1]; // Similarly for storeAudit #endif - currAttachment.handle = fragment.resource; - currAttachment.mipLevel = fragment.mipLevel; - currAttachment.depthSlice = fragment.depthSlice; - - // Don't care by default - currAttachment.loadAction = UnityEngine.Rendering.RenderBufferLoadAction.DontCare; - currAttachment.storeAction = UnityEngine.Rendering.RenderBufferStoreAction.DontCare; // Writing by-default has to preserve the contents, think rendering only a few small triangles on top of a big framebuffer // So it means we need to load/clear contents potentially. // If a user pass knows it will write all pixels in a buffer (like a blit) it can use the WriteAll/Discard usage to indicate this to the graph - bool partialWrite = fragment.accessFlags.HasFlag(AccessFlags.Write) && !fragment.accessFlags.HasFlag(AccessFlags.Discard); + bool partialWrite = fragment.accessFlags.HasFlag(AccessFlags.Write) + && !fragment.accessFlags.HasFlag(AccessFlags.Discard); ref readonly var resourceData = ref contextData.UnversionedResourceData(fragment.resource); bool isImported = resourceData.isImported; @@ -847,27 +847,26 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler int destroyPassID = resourceData.lastUsePassID; bool usedAfterThisNativePass = (destroyPassID >= (nativePass.lastGraphPass + 1)); + // Read or partial-write logic if (fragment.accessFlags.HasFlag(AccessFlags.Read) || partialWrite) { // The resource is already allocated before this pass so we need to load it if (resourceData.firstUsePassID < nativePass.firstGraphPass) { - currAttachment.loadAction = UnityEngine.Rendering.RenderBufferLoadAction.Load; + loadAction = RenderBufferLoadAction.Load; #if UNITY_EDITOR currLoadAudit = new LoadAudit(LoadReason.LoadPreviouslyWritten, resourceData.firstUsePassID); #endif - // Once we decide to load a resource, we must default to the Store action if the resource is used after the current native pass. // If we were to use the DontCare action in this case, the driver would be effectively be allowed to discard the // contents of the resource. This is true even when we're only performing reads on it. if (usedAfterThisNativePass) { - currAttachment.storeAction = RenderBufferStoreAction.Store; + storeAction = RenderBufferStoreAction.Store; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.StoreUsedByLaterPass, destroyPassID); #endif } - } // It's first used this native pass so we need to clear it so reads/partial writes return the correct clear value // the clear colors are part of the resource description and set-up when executing the graph we don't need to care about that here. @@ -878,14 +877,14 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Check if the user indicated he wanted clearing of his imported resource on it's first use by the graph if (resourceData.clear) { - currAttachment.loadAction = UnityEngine.Rendering.RenderBufferLoadAction.Clear; + loadAction = RenderBufferLoadAction.Clear; #if UNITY_EDITOR currLoadAudit = new LoadAudit(LoadReason.ClearImported); #endif } else { - currAttachment.loadAction = UnityEngine.Rendering.RenderBufferLoadAction.Load; + loadAction = RenderBufferLoadAction.Load; #if UNITY_EDITOR currLoadAudit = new LoadAudit(LoadReason.LoadImported); #endif @@ -894,7 +893,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler else { // Created by the graph internally clear on first read - currAttachment.loadAction = UnityEngine.Rendering.RenderBufferLoadAction.Clear; + loadAction = RenderBufferLoadAction.Clear; #if UNITY_EDITOR currLoadAudit = new LoadAudit(LoadReason.ClearCreated); #endif @@ -902,6 +901,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } + // Write logic if (fragment.accessFlags.HasFlag(AccessFlags.Write)) { // Simple non-msaa case @@ -910,7 +910,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (usedAfterThisNativePass) { // The resource is still used after this native pass so we need to store it. - currAttachment.storeAction = RenderBufferStoreAction.Store; + storeAction = RenderBufferStoreAction.Store; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.StoreUsedByLaterPass, destroyPassID); #endif @@ -927,14 +927,14 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { if (resourceData.discard) { - currAttachment.storeAction = RenderBufferStoreAction.DontCare; + storeAction = RenderBufferStoreAction.DontCare; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.DiscardImported); #endif } else { - currAttachment.storeAction = RenderBufferStoreAction.Store; + storeAction = RenderBufferStoreAction.Store; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.StoreImported); #endif @@ -942,7 +942,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } else { - currAttachment.storeAction = RenderBufferStoreAction.DontCare; + storeAction = RenderBufferStoreAction.DontCare; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.DiscardUnused); #endif @@ -957,11 +957,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // With MSAA we may access the resolved data for longer than the MSAA data so we track the destroyPass and lastPassThatNeedsUnresolved separately // In theory the opposite could also be true (use MSAA after resolve data is no longer needed) but we consider it sufficiently strange to not // consider it here. - - currAttachment.storeAction = RenderBufferStoreAction.DontCare; - + storeAction = RenderBufferStoreAction.DontCare; //Check if we're the last pass writing it by checking the output version of the current pass is the higherst version the resource will reach - bool lastWriter = (resourceData.latestVersionNumber == fragment.resource.version); // Cheaper but same? = resourceData.lastWritePassID >= pass.firstGraphPass && resourceData.lastWritePassID < pass.firstGraphPass + pass.numSubPasses; + bool lastWriter = (resourceData.latestVersionNumber == fragment.resource.version); + // Cheaper but same? = resourceData.lastWritePassID >= pass.firstGraphPass && resourceData.lastWritePassID < pass.firstGraphPass + pass.numSubPasses; bool isImportedLastWriter = isImported && lastWriter; // Used outside this native render pass, we need to store something @@ -969,7 +968,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { // Assume nothing is needed unless we are an imported texture (which doesn't require discarding) and we're the last ones writing it bool needsMSAASamples = isImportedLastWriter && !resourceData.discard; - bool needsResolvedData = isImportedLastWriter && (resourceData.bindMS == false);//bindMS never resolves + bool needsResolvedData = isImportedLastWriter && (resourceData.bindMS == false); int userPassID = 0; int msaaUserPassID = 0; @@ -978,7 +977,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler foreach (ref readonly var reader in contextData.Readers(fragment.resource)) { ref var readerPass = ref contextData.passData.ElementAt(reader.passId); - bool isFragment = readerPass.IsUsedAsFragment(fragment.resource, contextData); + bool isFragmentUsed = readerPass.IsUsedAsFragment(fragment.resource, contextData); // Unsafe pass - we cannot know how it is used, so we need to both store and resolve if (readerPass.type == RenderGraphPassType.Unsafe) @@ -990,7 +989,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler break; } // A fragment attachment use we need the msaa samples - else if (isFragment) + if (isFragmentUsed) { needsMSAASamples = true; msaaUserPassID = reader.passId; @@ -1014,32 +1013,39 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (needsMSAASamples && needsResolvedData) { - currAttachment.storeAction = RenderBufferStoreAction.StoreAndResolve; + storeAction = RenderBufferStoreAction.StoreAndResolve; #if UNITY_EDITOR currStoreAudit = new StoreAudit( - (isImportedLastWriter) ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass, userPassID, - (isImportedLastWriter) ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass, msaaUserPassID); + (isImportedLastWriter ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass), + userPassID, + (isImportedLastWriter ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass), + msaaUserPassID); #endif } else if (needsResolvedData) { - currAttachment.storeAction = RenderBufferStoreAction.Resolve; + storeAction = RenderBufferStoreAction.Resolve; #if UNITY_EDITOR - currStoreAudit = new StoreAudit((isImportedLastWriter) ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass, userPassID, StoreReason.DiscardUnused); + currStoreAudit = new StoreAudit( + (isImportedLastWriter ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass), + userPassID, + StoreReason.DiscardUnused); #endif } else if (needsMSAASamples) { - currAttachment.storeAction = RenderBufferStoreAction.Store; + storeAction = RenderBufferStoreAction.Store; #if UNITY_EDITOR currStoreAudit = new StoreAudit( - (resourceData.bindMS) ? StoreReason.DiscardBindMs : StoreReason.DiscardUnused, -1, - (isImportedLastWriter) ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass, msaaUserPassID); + (resourceData.bindMS ? StoreReason.DiscardBindMs : StoreReason.DiscardUnused), + -1, + (isImportedLastWriter ? StoreReason.StoreImported : StoreReason.StoreUsedByLaterPass), + msaaUserPassID); #endif } else { - Debug.Assert(false, "Resource was not destroyed but nobody seems to be using it!??"); + Debug.Assert(false, "Resource was not destroyed but nobody seems to be using it?!"); } } else if (isImportedLastWriter) @@ -1051,14 +1057,14 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { if (resourceData.discard) { - currAttachment.storeAction = RenderBufferStoreAction.DontCare; + storeAction = RenderBufferStoreAction.DontCare; #if UNITY_EDITOR currStoreAudit = new StoreAudit(StoreReason.DiscardImported); #endif } else { - currAttachment.storeAction = RenderBufferStoreAction.Store; + storeAction = RenderBufferStoreAction.Store; #if UNITY_EDITOR currStoreAudit = new StoreAudit( StoreReason.DiscardBindMs, -1, StoreReason.StoreImported); @@ -1072,11 +1078,13 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (resourceData.discard) { // Depth attachment always comes first if existing - bool isDepthAttachment = (nativePass.hasDepth && idx == 0); + bool isDepthAttachment = (nativePass.hasDepth && nativePass.attachments.size == 0); // For color attachment, we only discard the MSAA buffers and keep the resolve texture // This is a design decision due to the restrictive ImportResourceParams API, it could be revised later - currAttachment.storeAction = isDepthAttachment ? RenderBufferStoreAction.DontCare : RenderBufferStoreAction.Resolve; + storeAction = isDepthAttachment + ? RenderBufferStoreAction.DontCare + : RenderBufferStoreAction.Resolve; #if UNITY_EDITOR currStoreAudit = new StoreAudit( StoreReason.DiscardImported, -1, StoreReason.DiscardImported); @@ -1084,7 +1092,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } else { - currAttachment.storeAction = RenderBufferStoreAction.StoreAndResolve; + storeAction = RenderBufferStoreAction.StoreAndResolve; #if UNITY_EDITOR currStoreAudit = new StoreAudit( StoreReason.StoreImported, -1, StoreReason.StoreImported); @@ -1097,13 +1105,27 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (resourceData.memoryLess) { - currAttachment.memoryless = true; + memoryless = true; + #if DEVELOPMENT_BUILD || UNITY_EDITOR // Ensure load/store actions are actually valid for memory less - if (currAttachment.loadAction == RenderBufferLoadAction.Load) throw new Exception("Resource was marked as memoryless but is trying to load."); - if (currAttachment.storeAction != RenderBufferStoreAction.DontCare) throw new Exception("Resource was marked as memoryless but is trying to store or resolve."); + if (loadAction == RenderBufferLoadAction.Load) + throw new Exception("Resource was marked as memoryless but is trying to load."); + if (storeAction != RenderBufferStoreAction.DontCare) + throw new Exception("Resource was marked as memoryless but is trying to store or resolve."); #endif } + + var newAttachment = new NativePassAttachment( + handle, + loadAction, + storeAction, + memoryless, + mipLevel, + depthSlice + ); + + nativePass.attachments.Add(newAttachment); } } } @@ -1122,9 +1144,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] - private void ValidateAttachment(in RenderTargetInfo attRenderTargetInfo, RenderGraphResourceRegistry resources, int nativePassWidth, int nativePassHeight, int nativePassMSAASamples, bool isVrs) + private void ValidateAttachment(in RenderTargetInfo attRenderTargetInfo, RenderGraphResourceRegistry resources, int nativePassWidth, int nativePassHeight, int nativePassMSAASamples, + bool isVrs) { - if(RenderGraph.enableValidityChecks) + if (RenderGraph.enableValidityChecks) { if (isVrs) { @@ -1150,13 +1173,12 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler ref var attachments = ref nativePass.attachments; var attachmentCount = attachments.size; - ref readonly var firstGraphPass = ref contextData.passData.ElementAt(nativePass.firstGraphPass); - var w = firstGraphPass.fragmentInfoWidth; - var h = firstGraphPass.fragmentInfoHeight; - var d = firstGraphPass.fragmentInfoVolumeDepth; - var s = firstGraphPass.fragmentInfoSamples; + var width = nativePass.width; + var height = nativePass.height; + var volumeDepth = nativePass.volumeDepth; + var samples = nativePass.samples; - ValidateNativePass(nativePass, w, h, d, s, attachmentCount); + ValidateNativePass(nativePass, width, height, volumeDepth, samples, attachmentCount); ref var nativeSubPasses = ref contextData.nativeSubPassData; NativeArray nativeSubPassArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(nativeSubPasses.GetUnsafeReadOnlyPtr() + nativePass.firstNativeSubPass, nativePass.numNativeSubPasses, Allocator.None); @@ -1186,12 +1208,12 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler m_BeginRenderPassAttachments.Resize(attachmentCount, NativeArrayOptions.UninitializedMemory); for (var i = 0; i < attachmentCount; ++i) { - ref var currAttachmentHandle = ref attachments[i].handle; + ref readonly var currAttachmentHandle = ref attachments[i].handle; resources.GetRenderTargetInfo(currAttachmentHandle, out var renderTargetInfo); bool isVrs = (i == nativePass.shadingRateImageIndex); - ValidateAttachment(renderTargetInfo, resources, w, h, s, isVrs); + ValidateAttachment(renderTargetInfo, resources, width, height, samples, isVrs); ref var currBeginAttachment = ref m_BeginRenderPassAttachments.ElementAt(i); currBeginAttachment = new AttachmentDescriptor(renderTargetInfo.format); @@ -1233,7 +1255,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler if (i == 0 && nativePass.hasDepth) { // TODO: There seems to be no clear depth specified ?!?! - currBeginAttachment.clearDepth = 1.0f;// desc.clearDepth; + currBeginAttachment.clearDepth = 1.0f; // desc.clearDepth; } else { @@ -1248,7 +1270,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler var graphPassNamesForDebugSpan = ReadOnlySpan.Empty; #if DEVELOPMENT_BUILD || UNITY_EDITOR - if(RenderGraph.enableValidityChecks) + if (RenderGraph.enableValidityChecks) { graphPassNamesForDebug.Clear(); @@ -1272,6 +1294,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Adding '/' in UTF8 nameBytes[startStr++] = (byte)(0x2F); } + // Rewriting last '/' to be the null terminator nameBytes[utf8CStrDebugNameLength - 1] = (byte)0; } @@ -1280,7 +1303,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } #endif - rgContext.cmd.BeginRenderPass(w, h, d, s, attachmentDescArray, depthAttachmentIndex, nativePass.shadingRateImageIndex, nativeSubPassArray, graphPassNamesForDebugSpan); + rgContext.cmd.BeginRenderPass(width, height, volumeDepth, samples, attachmentDescArray, depthAttachmentIndex, nativePass.shadingRateImageIndex, nativeSubPassArray, graphPassNamesForDebugSpan); #if ENABLE_UNITY_COLLECTIONS_CHECKS AtomicSafetyHandle.Release(safetyHandle); @@ -1353,7 +1376,6 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { cmd.SetRandomWriteTarget(index, buff, false); } - } else { @@ -1419,7 +1441,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler var isRaster = pass.type == RenderGraphPassType.Raster; - ExecuteCreateRessource(rgContext, resources, pass); + ExecuteInitializeResource(rgContext, resources, pass); var isAsyncCompute = pass.type == RenderGraphPassType.Compute && pass.asyncCompute == true; if (isAsyncCompute) @@ -1463,6 +1485,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { throw new Exception("Compiler error: Pass is marked as beginning a native sub pass but no pass is currently active."); } + rgContext.cmd.NextSubPass(); } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs index 4a65850f..2d727c66 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs @@ -10,26 +10,44 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { // Per pass info on inputs to the pass [DebuggerDisplay("PassInputData: Res({resource.index})")] - internal struct PassInputData + internal readonly struct PassInputData { - public ResourceHandle resource; + public readonly ResourceHandle resource; + + public PassInputData(ResourceHandle resource) + { + this.resource = resource; + } } // Per pass info on outputs to the pass [DebuggerDisplay("PassOutputData: Res({resource.index})")] - internal struct PassOutputData + internal readonly struct PassOutputData { - public ResourceHandle resource; + public readonly ResourceHandle resource; + + public PassOutputData(ResourceHandle resource) + { + this.resource = resource; + } } // Per pass fragment (attachment) info [DebuggerDisplay("PassFragmentData: Res({resource.index}):{accessFlags}")] - internal struct PassFragmentData + internal readonly struct PassFragmentData { - public ResourceHandle resource; - public AccessFlags accessFlags; - public int mipLevel; - public int depthSlice; + public readonly ResourceHandle resource; + public readonly AccessFlags accessFlags; + public readonly int mipLevel; + public readonly int depthSlice; + + public PassFragmentData(ResourceHandle handle, AccessFlags flags, int mipLevel, int depthSlice) + { + resource = handle; + accessFlags = flags; + this.mipLevel = mipLevel; + this.depthSlice = depthSlice; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() @@ -55,11 +73,18 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Per pass random write texture info [DebuggerDisplay("PassRandomWriteData: Res({resource.index}):{index}:{preserveCounterValue}")] - internal struct PassRandomWriteData + internal readonly struct PassRandomWriteData { - public ResourceHandle resource; - public int index; - public bool preserveCounterValue; + public readonly ResourceHandle resource; + public readonly int index; + public readonly bool preserveCounterValue; + + public PassRandomWriteData(ResourceHandle resource, int index, bool preserveCounterValue) + { + this.resource = resource; + this.index = index; + this.preserveCounterValue = preserveCounterValue; + } public override int GetHashCode() { @@ -240,7 +265,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler => ctx.fragmentData.MakeReadOnlySpan(firstFragment, numFragments); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public PassFragmentData ShadingRateImage(CompilerContextData ctx) + public readonly PassFragmentData ShadingRateImage(CompilerContextData ctx) => ctx.fragmentData[shadingRateImageIndex]; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -253,7 +278,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Loop over this pass's random write textures returned as PassFragmentData public ReadOnlySpan RandomWriteTextures(CompilerContextData ctx) - => ctx.randomAccessResourceData.MakeReadOnlySpan(firstRandomAccessResource, numRandomAccessResources); + => ctx.randomAccessResourceData.MakeReadOnlySpan(firstRandomAccessResource, numRandomAccessResources); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ReadOnlySpan LastUsedResources(CompilerContextData ctx) @@ -392,14 +417,24 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Data per attachment of a native renderpass [DebuggerDisplay("Res({handle.index}) : {loadAction} : {storeAction} : {memoryless}")] - internal struct NativePassAttachment + internal readonly struct NativePassAttachment { - public ResourceHandle handle; - public UnityEngine.Rendering.RenderBufferLoadAction loadAction; - public UnityEngine.Rendering.RenderBufferStoreAction storeAction; - public bool memoryless; - public int mipLevel; - public int depthSlice; + public readonly ResourceHandle handle; + public readonly RenderBufferLoadAction loadAction; + public readonly RenderBufferStoreAction storeAction; + public readonly bool memoryless; + public readonly int mipLevel; + public readonly int depthSlice; + + public NativePassAttachment(ResourceHandle handle, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction, bool memoryless, int mipLevel, int depthSlice) + { + this.handle = handle; + this.loadAction = loadAction; + this.storeAction = storeAction; + this.memoryless = memoryless; + this.mipLevel = mipLevel; + this.depthSlice = depthSlice; + } } internal enum LoadReason @@ -415,7 +450,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } [DebuggerDisplay("{reason} : {passId}")] - internal struct LoadAudit + internal readonly struct LoadAudit { public static readonly string[] LoadReasonMessages = { "Invalid reason", @@ -426,8 +461,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler "The pass indicated it will rewrite the full resource contents. Existing contents are not loaded or cleared.", }; - public LoadReason reason; - public int passId; + public readonly LoadReason reason; + public readonly int passId; public LoadAudit(LoadReason setReason, int setPassId = -1) { @@ -455,7 +490,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } [DebuggerDisplay("{reason} : {passId} / MSAA {msaaReason} : {msaaPassId}")] - internal struct StoreAudit + internal readonly struct StoreAudit { public static readonly string[] StoreReasonMessages = { "Invalid reason", @@ -467,10 +502,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler "The resource is a single sample resource, there is no multi-sample data to handle.", }; - public StoreReason reason; - public int passId; - public StoreReason msaaReason; - public int msaaPassId; + public readonly StoreReason reason; + public readonly int passId; + public readonly StoreReason msaaReason; + public readonly int msaaPassId; public StoreAudit(StoreReason setReason, int setPassId = -1, StoreReason setMsaaReason = StoreReason.NoMSAABuffer, int setMsaaPassId = -1) { @@ -506,10 +541,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } [DebuggerDisplay("{reason} : {breakPass}")] - internal struct PassBreakAudit + internal readonly struct PassBreakAudit { - public PassBreakReason reason; - public int breakPass; + public readonly PassBreakReason reason; + public readonly int breakPass; public PassBreakAudit(PassBreakReason reason, int breakPass) { @@ -576,7 +611,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler firstGraphPass = pass.passId; lastGraphPass = pass.passId; numGraphPasses = 1; - firstNativeSubPass = -1;// Set up during compile + firstNativeSubPass = -1; // Set up during compile numNativeSubPasses = 0; fragments = new FixedAttachmentArray(); @@ -701,7 +736,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // This function does not modify the current render graph state, it only evaluates and returns the correct PassBreakAudit public static PassBreakAudit CanMerge(CompilerContextData contextData, int activeNativePassId, int passIdToMerge) { - ref readonly var passToMerge = ref contextData.passData.ElementAt(passIdToMerge); + ref var passToMerge = ref contextData.passData.ElementAt(passIdToMerge); // Non raster passes (low level, compute,...) will break the native pass chain // as they may need to do SetRendertarget or non-fragment work @@ -710,7 +745,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler return new PassBreakAudit(PassBreakReason.NonRasterPass, passIdToMerge); } - ref readonly var nativePass = ref contextData.nativePassData.ElementAt(activeNativePassId); + ref var nativePass = ref contextData.nativePassData.ElementAt(activeNativePassId); // If a pass has no fragment attachments a lot of the tests can be skipped // You could argue that a raster pass with no fragments is not allowed but why not? @@ -798,6 +833,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } + // Gather which attachments to add to the current renderpass var attachmentsToTryAdding = new FixedAttachmentArray(); @@ -833,6 +869,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } } + foreach (ref readonly var fragmentInput in passToMerge.FragmentInputs(contextData)) { @@ -864,8 +901,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler } } - bool canMergeNativeSubPass = CanMergeNativeSubPass(contextData, nativePass, passToMerge); - if (!canMergeNativeSubPass && nativePass.numGraphPasses + 1 > NativePassCompiler.k_MaxSubpass) + // We check first if we are at risk of having too many subpasses, + // only then we do the costlier subpass merging check, short circuiting it whenever possible + bool canAddAnExtraSubpass = (nativePass.numGraphPasses < NativePassCompiler.k_MaxSubpass); + if (!canAddAnExtraSubpass && !CanMergeNativeSubPass(contextData, ref nativePass, ref passToMerge)) { return new PassBreakAudit(PassBreakReason.SubPassLimitReached, passIdToMerge); } @@ -876,7 +915,8 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // This function follows the structure of TryMergeNativeSubPass but only tests if the new native subpass can be // merged with the last one, allowing for early returns. It does not modify the state - static bool CanMergeNativeSubPass(CompilerContextData contextData, NativePassData nativePass, PassData passToMerge) + // ref for nativePass is used for performance reasons. The method should not modify nativePass. + static bool CanMergeNativeSubPass(CompilerContextData contextData, ref NativePassData nativePass, ref PassData passToMerge) { // We have no output attachments, this is an "empty" raster pass doing only non-rendering command so skip it. if (passToMerge.numFragments == 0 && passToMerge.numFragmentInputs == 0) @@ -884,103 +924,101 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler return true; } + // Nothing to merge with if (nativePass.numNativeSubPasses == 0) { - return false; // nothing to merge with + return false; } - ref readonly var fragmentList = ref nativePass.fragments; - ref readonly var lastPass = ref contextData.nativeSubPassData.ElementAt(nativePass.firstNativeSubPass + + ref var lastPass = ref contextData.nativeSubPassData.ElementAt(nativePass.firstNativeSubPass + nativePass.numNativeSubPasses - 1); - // NOTE: Not all graph subpasses get an actual native pass: - // - There could be passes that do only non-raster ops (like setglobal) and have no attachments. They don't get a native pass - // - Renderpasses that use exactly the same rendertargets at the previous pass use the same native pass. This is because - // nextSubpass is expensive on some platforms (even if its' essentially a no-op as it's using the same attachments). + bool currRenderGraphPassHasDepth = passToMerge.fragmentInfoHasDepth; + + // If any output attachments, they must match existing ones in the subpass + // Doing an early return if the count differs + int colorOffset = currRenderGraphPassHasDepth ? -1 : 0; + int colorOutputsLength = passToMerge.numFragments + colorOffset; + if (colorOutputsLength != lastPass.colorOutputs.Length) + { + return false; + } + + // If any input attachments, they must match existing ones in the subpass + // Doing an early return if the count differs + int inputsLength = passToMerge.numFragmentInputs; + if (inputsLength != lastPass.inputs.Length) + { + return false; + } + SubPassFlags flags = SubPassFlags.None; // If depth ends up being bound only because of merging - if (!passToMerge.fragmentInfoHasDepth && nativePass.hasDepth) + if (!currRenderGraphPassHasDepth && nativePass.hasDepth) { // Set SubPassFlags to best match the pass we are trying to merge with flags = nativePass.GetSubPassFlagForMerging(); } - // MRT attachments - { - int fragmentIdx = 0; - int colorOffset = (passToMerge.fragmentInfoHasDepth) ? -1 : 0; - int colorOutputsLength = passToMerge.numFragments + colorOffset; + ref readonly var fragmentList = ref nativePass.fragments; - if (colorOutputsLength != lastPass.colorOutputs.Length) + // MRT attachments + int fragmentIdx = 0; + foreach (ref readonly var graphPassFragment in passToMerge.Fragments(contextData)) + { + // Check if we're handling the depth attachment + if (currRenderGraphPassHasDepth && fragmentIdx == 0) { - return false; + flags = (graphPassFragment.accessFlags.HasFlag(AccessFlags.Write)) + ? SubPassFlags.None + : SubPassFlags.ReadOnlyDepth; } - - foreach (ref readonly var graphPassFragment in passToMerge.Fragments(contextData)) + // It's a color attachment + else { - // Check if we're handling the depth attachment - if (passToMerge.fragmentInfoHasDepth && fragmentIdx == 0) - { - flags = (graphPassFragment.accessFlags.HasFlag(AccessFlags.Write)) - ? SubPassFlags.None - : SubPassFlags.ReadOnlyDepth; - } - // It's a color attachment - else + // Find the index of this subpass attachment in the native renderpass attachment list + int colorAttachmentIdx = -1; + for (int fragmentId = 0; fragmentId < fragmentList.size; ++fragmentId) { - // Find the index of this subpass's attachment in the native renderpass attachment list - int colorAttachmentIdx = -1; - for (int fragmentId = 0; fragmentId < fragmentList.size; ++fragmentId) + if (PassFragmentData.SameSubResource(fragmentList[fragmentId], graphPassFragment)) { - if (PassFragmentData.SameSubResource(fragmentList[fragmentId], graphPassFragment)) - { - colorAttachmentIdx = fragmentId; - break; - } - } - - if (colorAttachmentIdx < 0 || colorAttachmentIdx != lastPass.colorOutputs[fragmentIdx + colorOffset]) - { - return false; + colorAttachmentIdx = fragmentId; + break; } } - fragmentIdx++; + if (colorAttachmentIdx < 0 || colorAttachmentIdx != lastPass.colorOutputs[fragmentIdx + colorOffset]) + { + return false; + } } + + fragmentIdx++; } + // FB-fetch attachments + int inputIndex = 0; + foreach (ref readonly var graphFragmentInput in passToMerge.FragmentInputs(contextData)) { - int inputIndex = 0; - int inputsLength = passToMerge.numFragmentInputs; - - if (inputsLength != lastPass.inputs.Length) + // Find the index of this subpass attachment in the native renderpass attachment list + int inputAttachmentIdx = -1; + for (int fragmentId = 0; fragmentId < fragmentList.size; ++fragmentId) { - return false; - } - - foreach (ref readonly var graphFragmentInput in passToMerge.FragmentInputs(contextData)) - { - // Find the index of this subpass's attachment in the native renderpass attachment list - int inputAttachmentIdx = -1; - for (int fragmentId = 0; fragmentId < fragmentList.size; ++fragmentId) + if (PassFragmentData.SameSubResource(fragmentList[fragmentId], graphFragmentInput)) { - if (PassFragmentData.SameSubResource(fragmentList[fragmentId], graphFragmentInput)) - { - inputAttachmentIdx = fragmentId; - break; - } - } - - // need to keep this - same comment as above - if (inputAttachmentIdx < 0 || inputAttachmentIdx != lastPass.inputs[inputIndex]) - { - return false; + inputAttachmentIdx = fragmentId; + break; } + } - inputIndex++; + if (inputAttachmentIdx < 0 || inputAttachmentIdx != lastPass.inputs[inputIndex]) + { + return false; } + + inputIndex++; } // last check for flags @@ -991,10 +1029,10 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler // Modifies the state public static void TryMergeNativeSubPass(CompilerContextData contextData, ref NativePassData nativePass, ref PassData passToMerge) { - ref readonly var fragmentList = ref nativePass.fragments; + ref var fragmentList = ref nativePass.fragments; // Only done once per native pass (on creation), should stay -1 if no fragments - if (nativePass is { numNativeSubPasses: 0, fragments: { size: > 0 } }) + if (nativePass.numNativeSubPasses == 0 && nativePass.fragments.size > 0) { nativePass.firstNativeSubPass = contextData.nativeSubPassData.Length; } @@ -1101,8 +1139,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler nativePass.numNativeSubPasses - 1))) { contextData.nativeSubPassData.Add(desc); - int idx = contextData.nativeSubPassData.LastIndex(); - Debug.Assert(idx == nativePass.firstNativeSubPass + nativePass.numNativeSubPasses); + Debug.Assert(contextData.nativeSubPassData.LastIndex() == nativePass.firstNativeSubPass + nativePass.numNativeSubPasses); nativePass.numNativeSubPasses++; passToMerge.beginNativeSubpass = true; @@ -1194,7 +1231,7 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler nativePass.numGraphPasses++; nativePass.lastGraphPass = passIdToMerge; - // Depth needs special handling if the native pass doesn't have depth and merges with a pass that does + // Depth needs special handling if the native pass doesn't have depth and merges with a graph pass that does // as we require the depth attachment to be at index 0 if (!nativePass.hasDepth && passToMerge.fragmentInfoHasDepth) { @@ -1210,24 +1247,25 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler for (int i = 0; i < nativePass.fragments.size; ++i) { ref var existingAttach = ref nativePass.fragments[i]; - if (PassFragmentData.SameSubResource(existingAttach, newAttach)) - { - var newAttachAccessFlags = newAttach.accessFlags; - // If the existing attachment accessFlag has Discard flag, remove Read flag from newAttach flags, as the content has not to be Loaded - if (existingAttach.accessFlags.HasFlag(AccessFlags.Discard)) - newAttachAccessFlags = newAttachAccessFlags & ~AccessFlags.Read; + if (!PassFragmentData.SameSubResource(existingAttach, newAttach)) + continue; - existingAttach.accessFlags |= newAttachAccessFlags; + var newAttachAccessFlags = newAttach.accessFlags; + // If the existing attachment accessFlag has Discard flag, remove Read flag from newAttach flags, as the content has not to be Loaded + if (existingAttach.accessFlags.HasFlag(AccessFlags.Discard)) + newAttachAccessFlags &= ~AccessFlags.Read; #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (existingAttach.resource.version > newAttach.resource.version) - throw new Exception("Adding an older version while a higher version is already registered with the pass."); + if (existingAttach.resource.version > newAttach.resource.version) + throw new Exception("Adding an older version while a higher version is already registered with the pass."); #endif - var prevAttachRes = existingAttach.resource; - existingAttach.resource = new ResourceHandle(prevAttachRes, newAttach.resource.version); - alreadyAttached = true; - break; - } + existingAttach = new PassFragmentData( + new ResourceHandle(existingAttach.resource, newAttach.resource.version), + existingAttach.accessFlags | newAttachAccessFlags, + existingAttach.mipLevel, + existingAttach.depthSlice); + alreadyAttached = true; + break; } if (!alreadyAttached) @@ -1243,24 +1281,26 @@ namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler for (int i = 0; i < nativePass.fragments.size; ++i) { ref var existingAttach = ref nativePass.fragments[i]; - if (PassFragmentData.SameSubResource(existingAttach, newAttach)) - { - var newAttachAccessFlags = newAttach.accessFlags; - // If the existing attachment accessFlag has Discard flag, remove Read flag from newAttach flags, as the content has not to be Loaded - if (existingAttach.accessFlags.HasFlag(AccessFlags.Discard)) - newAttachAccessFlags = newAttachAccessFlags & ~AccessFlags.Read; + if (!PassFragmentData.SameSubResource(existingAttach, newAttach)) + continue; - existingAttach.accessFlags |= newAttachAccessFlags; + var newAttachAccessFlags = newAttach.accessFlags; + // If the existing attachment accessFlag has Discard flag, remove Read flag from newAttach flags, as the content has not to be Loaded + if (existingAttach.accessFlags.HasFlag(AccessFlags.Discard)) + newAttachAccessFlags &= ~AccessFlags.Read; #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (existingAttach.resource.version > newAttach.resource.version) - throw new Exception("Adding an older version while a higher version is already registered with the pass."); + if (existingAttach.resource.version > newAttach.resource.version) + throw new Exception("Adding an older version while a higher version is already registered with the pass."); #endif - var prevAttachRes = existingAttach.resource; - existingAttach.resource = new ResourceHandle(prevAttachRes, newAttach.resource.version); - alreadyAttached = true; - break; - } + + existingAttach = new PassFragmentData( + new ResourceHandle(existingAttach.resource, newAttach.resource.version), + existingAttach.accessFlags | newAttachAccessFlags, + existingAttach.mipLevel, + existingAttach.depthSlice); + alreadyAttached = true; + break; } if (!alreadyAttached) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs index 1e26f847..3464f0bd 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using UnityEngine.Rendering.RenderGraphModule; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; @@ -7,6 +8,7 @@ namespace UnityEngine.Rendering /// /// Render Graph-related Rendering Debugger settings. /// + [CurrentPipelineHelpURL(pageName: "features/rendering-debugger-reference", pageHash: "render-graph")] class DebugDisplaySettingsRenderGraph : IDebugDisplaySettingsData { public DebugDisplaySettingsRenderGraph() @@ -17,25 +19,30 @@ namespace UnityEngine.Rendering } } - [DisplayInfo(name = "Render Graph", order = 10)] - [CurrentPipelineHelpURL(pageName: "features/rendering-debugger-reference", pageHash: "render-graph")] + [DisplayInfo(name = "Rendering", order = 10)] private class SettingsPanel : DebugDisplaySettingsPanel { - public override string PanelName => "Render Graph"; public SettingsPanel(DebugDisplaySettingsRenderGraph _) { + var foldout = new DebugUI.Foldout() + { + displayName = "Render Graph", + documentationUrl = typeof(DebugDisplaySettingsRenderGraph).GetCustomAttribute()?.URL + }; + AddWidget(foldout); + bool usingRenderGraph = false; foreach (var graph in RenderGraph.GetRegisteredRenderGraphs()) { usingRenderGraph = true; var list = graph.GetWidgetList(); foreach (var item in list) - AddWidget(item); + foldout.children.Add(item); } if (!usingRenderGraph) { - AddWidget(new DebugUI.MessageBox() + foldout.children.Add(new DebugUI.MessageBox() { displayName = "Warning: The current render pipeline does not have Render Graphs Registered", diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs index be738e2c..5283d470 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs @@ -13,10 +13,17 @@ namespace UnityEngine.Rendering.RenderGraphModule public bool disablePassCulling; public bool disablePassMerging; public bool immediateMode; - public bool enableLogging; public bool logFrameInformation; public bool logResources; + public bool enableLogging => logFrameInformation || logResources; + + public void ResetLogging() + { + logFrameInformation = false; + logResources = false; + } + internal void Reset() { clearRenderTargetsAtCreation = false; @@ -24,9 +31,8 @@ namespace UnityEngine.Rendering.RenderGraphModule disablePassCulling = false; disablePassMerging = false; immediateMode = false; - enableLogging = false; - logFrameInformation = false; - logResources = false; + + ResetLogging(); } private static class Strings @@ -39,7 +45,6 @@ namespace UnityEngine.Rendering.RenderGraphModule public static readonly NameAndTooltip EnableLogging = new() { name = "Enable Logging", tooltip = "Enable to allow HDRP to capture information in the log." }; public static readonly NameAndTooltip LogFrameInformation = new() { name = "Log Frame Information", tooltip = "Enable to log information output from each frame." }; public static readonly NameAndTooltip LogResources = new() { name = "Log Resources", tooltip = "Enable to log the current render graph's global resource usage." }; - public static readonly NameAndTooltip EnableNativeCompiler = new() { name = "Enable Native Pass Compiler", tooltip = "Enable the new native pass compiler." }; } internal List GetWidgetList(string name) @@ -75,7 +80,8 @@ namespace UnityEngine.Rendering.RenderGraphModule { nameAndTooltip = Strings.DisablePassMerging, getter = () => disablePassMerging, - setter = value => disablePassMerging = value + setter = value => disablePassMerging = value, + isHiddenCallback = () => !RenderGraph.hasAnyRenderGraphWithNativeRenderPassesEnabled }, new DebugUI.BoolField { @@ -85,19 +91,11 @@ namespace UnityEngine.Rendering.RenderGraphModule // [UUM-64948] Temporarily disable for URP while we implement support for Immediate Mode in the RenderGraph isHiddenCallback = () => !IsImmediateModeSupported() }, - new DebugUI.BoolField - { - nameAndTooltip = Strings.EnableLogging, - getter = () => enableLogging, - setter = value => enableLogging = value - }, new DebugUI.Button { nameAndTooltip = Strings.LogFrameInformation, action = () => { - if (!enableLogging) - Debug.Log("You must first enable logging before logging frame information."); logFrameInformation = true; #if UNITY_EDITOR UnityEditor.SceneView.RepaintAll(); @@ -109,8 +107,6 @@ namespace UnityEngine.Rendering.RenderGraphModule nameAndTooltip = Strings.LogResources, action = () => { - if (!enableLogging) - Debug.Log("You must first enable logging before logging resources."); logResources = true; #if UNITY_EDITOR UnityEditor.SceneView.RepaintAll(); @@ -134,8 +130,11 @@ namespace UnityEngine.Rendering.RenderGraphModule { var list = GetWidgetList(name); m_DebugItems = list.ToArray(); - m_DebugPanel = debugPanel != null ? debugPanel : DebugManager.instance.GetPanel(name.Length == 0 ? "Render Graph" : name, true); - m_DebugPanel.children.Add(m_DebugItems); + m_DebugPanel = debugPanel != null ? debugPanel : DebugManager.instance.GetPanel(name.Length == 0 ? "Rendering" : name, true); + + var foldout = new DebugUI.Foldout() { displayName = name, }; + foldout.children.Add(m_DebugItems); + m_DebugPanel.children.Add(foldout); } public void UnRegisterDebug(string name) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs new file mode 100644 index 00000000..ee527381 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace UnityEngine.Rendering.RenderGraphModule +{ + public partial class RenderGraph + { + internal static class RenderGraphExceptionMessages + { + internal static bool enableCaller = true; + + internal const string k_RenderGraphExecutionError = "Render Graph Execution error"; + + static readonly Dictionary m_RenderGraphStateMessages = new() + { + { RenderGraphState.RecordingPass, "This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass()." }, + { RenderGraphState.RecordingGraph, "This API cannot be called during the Render Graph high-level recording step, please call it within AddUnsafePass()/AddComputePass()/AddRasterRenderPass() or outside of RecordRenderGraph()." }, + { RenderGraphState.RecordingPass | RenderGraphState.Executing, "This API cannot be called when Render Graph records a pass or executes it, please call it outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass()." }, + { RenderGraphState.Executing, "This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc()." }, + { RenderGraphState.Active, "This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph()." } + }; + + const string k_ErrorDefaultMessage = "Invalid render graph state, impossible to log the exception."; + + internal static string GetExceptionMessage(RenderGraphState state) + { + string caller = GetHigherCaller(); + if (!m_RenderGraphStateMessages.TryGetValue(state, out var messageException)) + { + return enableCaller ? $"[{caller}] {k_ErrorDefaultMessage}" : k_ErrorDefaultMessage; + } + + return enableCaller ? $"[{caller}] {messageException}" : messageException; + } + + static string GetHigherCaller() + { + // k_CurrentStackCaller is used here to skip three levels in the call stack: + // Level 0: GetHigherCaller() itself. + // Level 1: GetExceptionMessage() or any other wrapper method that calls GetHigherCaller(). + // Level 2: The function that directly calls GetMessage() (e.g CheckNotUsedWhenExecute). + // Level 3: The actual function we are interested in, our public API. + const int k_CurrentStackCaller = 3; + + var stackTrace = new StackTrace(k_CurrentStackCaller, false); + + if (stackTrace.FrameCount > 0) + { + var frame = stackTrace.GetFrame(0); + return frame?.GetMethod()?.Name ?? "UnknownCaller"; + } + + return "UnknownCaller"; + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs.meta new file mode 100644 index 00000000..7ba09e5b --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.ExceptionMessages.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f658c411e0892ba499e17093373f687b \ No newline at end of file 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 8913e109..879207a0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs @@ -48,6 +48,35 @@ namespace UnityEngine.Rendering.RenderGraphModule ReadWrite = Read | Write } + [Flags] + internal enum RenderGraphState + { + /// + /// Render Graph is not doing anything. + /// + Idle = 0, + + /// + /// Render Graph is recording the graph. + /// + RecordingGraph = 1 << 0, + + /// + /// Render Graph is recording a low level pass. + /// + RecordingPass = 1 << 1, + + /// + /// Render Graph is executing the graph. + /// + Executing = 1 << 2, + + /// + /// Utility flag to check if the graph is active. + /// + Active = RecordingGraph | RecordingPass | Executing + } + /// /// An object representing the internal context of a rendergraph pass execution. /// This object is public for technical reasons only and should not be used. @@ -372,6 +401,17 @@ namespace UnityEngine.Rendering.RenderGraphModule get; set; } + internal static bool hasAnyRenderGraphWithNativeRenderPassesEnabled + { + get + { + foreach (var graph in s_RegisteredGraphs) + if (graph.nativeRenderPassesEnabled) + return true; + return false; + } + } + internal/*for tests*/ RenderGraphResourceRegistry m_Resources; RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool(); RenderGraphBuilders m_builderInstance = new RenderGraphBuilders(); @@ -442,12 +482,12 @@ namespace UnityEngine.Rendering.RenderGraphModule int m_CurrentFrameIndex; int m_CurrentImmediatePassIndex; bool m_ExecutionExceptionWasRaised; - bool m_HasRenderGraphBegun; bool m_RendererListCulling; bool m_EnableCompilationCaching; CompiledGraph m_DefaultCompiledGraph = new(); CompiledGraph m_CurrentCompiledGraph; string m_CaptureDebugDataForExecution; // Null unless debug data has been requested + RenderGraphState m_RenderGraphState; Dictionary m_DebugData = new Dictionary(); @@ -464,6 +504,12 @@ namespace UnityEngine.Rendering.RenderGraphModule m_CaptureDebugDataForExecution = executionName; } + internal RenderGraphState RenderGraphState + { + get { return m_RenderGraphState; } + set { m_RenderGraphState = value; } + } + /// If true, the Render Graph Viewer is active. public static bool isRenderGraphViewerActive { get; internal set; } @@ -508,12 +554,29 @@ namespace UnityEngine.Rendering.RenderGraphModule m_Resources = new RenderGraphResourceRegistry(m_DebugParameters, m_FrameInformationLogger); s_RegisteredGraphs.Add(this); onGraphRegistered?.Invoke(this); + + m_RenderGraphState = RenderGraphState.Idle; + + RenderGraph.RenderGraphExceptionMessages.enableCaller = true; } /// /// Cleanup the Render Graph. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// public void Cleanup() + { + CheckNotUsedWhenActive(); + + ForceCleanup(); + } + + // Internal, only for testing + // Useful when we need to clean when calling + // internal functions in tests even if Render Graph is active + internal void ForceCleanup() { // Usually done at the end of Execute step // Also doing it here in case RG stopped before it @@ -545,17 +608,27 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Register the render graph to the debug window. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// /// Optional debug panel to which the render graph debug parameters will be registered. public void RegisterDebug(DebugUI.Panel panel = null) { + CheckNotUsedWhenActive(); + m_DebugParameters.RegisterDebug(name, panel); } /// /// Unregister render graph from the debug window. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// public void UnRegisterDebug() { + CheckNotUsedWhenActive(); + m_DebugParameters.UnRegisterDebug(this.name); } @@ -584,30 +657,36 @@ namespace UnityEngine.Rendering.RenderGraphModule /// End frame processing. Purge resources that have been used since last frame and resets internal states. /// This need to be called once per frame. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// public void EndFrame() { + CheckNotUsedWhenActive(); + m_Resources.PurgeUnusedGraphicsResources(); if (m_DebugParameters.logFrameInformation) - { - Debug.Log(m_FrameInformationLogger.GetAllLogs()); - m_DebugParameters.logFrameInformation = false; - } + m_FrameInformationLogger.FlushLogs(); if (m_DebugParameters.logResources) - { m_Resources.FlushLogs(); - m_DebugParameters.logResources = false; - } + + m_DebugParameters.ResetLogging(); } /// /// Import an external texture to the Render Graph. /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// External RTHandle that needs to be imported. /// A new TextureHandle that represents the imported texture in the context of this rendergraph. public TextureHandle ImportTexture(RTHandle rt) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportTexture(rt); } @@ -632,15 +711,19 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Note: RTHandles that wrap RenderTargetIdentifier will fail to import using this overload as render graph can't derive the render texture's properties. /// In that case the overload taking a RenderTargetInfo argument should be used instead. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// External RTHandle that needs to be imported. /// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware. /// A new TextureHandle that represents the imported texture in the context of this rendergraph. public TextureHandle ImportTexture(RTHandle rt, ImportResourceParams importParams ) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportTexture(rt, importParams); } - /// /// Import an external texture to the Render Graph. This overload should be used for RTHandles wrapping a RenderTargetIdentifier. /// If the RTHandle is wrapping a RenderTargetIdentifer, Rendergrpah can't derive the render texture's properties so the user has to provide this info to the graph through RenderTargetInfo. @@ -650,12 +733,17 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Note: To avoid inconsistencies between the passed in RenderTargetInfo and render texture this overload can only be used when the RTHandle is wrapping a RenderTargetIdentifier. /// If this is not the case, the overload of ImportTexture without a RenderTargetInfo argument should be used instead. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// External RTHandle that needs to be imported. /// The properties of the passed in RTHandle. /// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware. /// A new TextureHandle that represents the imported texture in the context of this rendergraph. public TextureHandle ImportTexture(RTHandle rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams() ) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportTexture(rt, info, importParams); } @@ -663,20 +751,33 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Import an external texture to the Render Graph and set the handle as builtin handle. This can only happen from within the graph module /// so it is internal. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// + /// External RTHandle that needs to be imported. + /// The handle is a builtin handle managed by RenderGraph internally. + /// A new TextureHandle that represents the imported texture in the context of this rendergraph. internal TextureHandle ImportTexture(RTHandle rt, bool isBuiltin) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportTexture(rt, isBuiltin); } /// /// Import the final backbuffer to render graph. The rendergraph can't derive the properties of a RenderTargetIdentifier as it is an opaque handle so the user has to pass them in through the info argument. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Backbuffer render target identifier. /// The properties of the passed in RTHandle. /// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware. /// A new TextureHandle that represents the imported texture in the context of this rendergraph. public TextureHandle ImportBackbuffer(RenderTargetIdentifier rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams()) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportBackbuffer(rt, info, importParams); } @@ -684,10 +785,15 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Import the final backbuffer to render graph. /// This function can only be used when nativeRenderPassesEnabled is false. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Backbuffer render target identifier. /// A new TextureHandle that represents the imported texture in the context of this rendergraph. public TextureHandle ImportBackbuffer(RenderTargetIdentifier rt) { + CheckNotUsedWhenExecuting(); + RenderTargetInfo dummy = new RenderTargetInfo(); dummy.width = dummy.height = dummy.volumeDepth = dummy.msaaSamples = 1; dummy.format = GraphicsFormat.R8G8B8A8_SRGB; @@ -697,10 +803,15 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Create a new Render Graph Texture resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Texture descriptor. /// A new TextureHandle. public TextureHandle CreateTexture(in TextureDesc desc) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateTexture(desc); } @@ -708,13 +819,15 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Create a new Render Graph Shared Texture resource. /// This texture will be persistent across render graph executions. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// /// Creation descriptor of the texture. /// Set to true if you want to manage the lifetime of the resource yourself. Otherwise the resource will be released automatically if unused for a time. /// A new TextureHandle. public TextureHandle CreateSharedTexture(in TextureDesc desc, bool explicitRelease = false) { - if (m_HasRenderGraphBegun) - throw new InvalidOperationException("A shared texture can only be created outside of render graph execution."); + CheckNotUsedWhenActive(); return m_Resources.CreateSharedTexture(desc, explicitRelease); } @@ -732,11 +845,13 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Release a Render Graph shared texture resource. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// /// The handle to the texture that needs to be release. public void ReleaseSharedTexture(TextureHandle texture) { - if (m_HasRenderGraphBegun) - throw new InvalidOperationException("A shared texture can only be release outside of render graph execution."); + CheckNotUsedWhenActive(); m_Resources.ReleaseSharedTexture(texture); } @@ -744,10 +859,15 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// 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. /// A new TextureHandle. public TextureHandle CreateTexture(TextureHandle texture) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateTexture(m_Resources.GetTextureResourceDesc(texture.handle)); } @@ -763,6 +883,8 @@ namespace UnityEngine.Rendering.RenderGraphModule /// A new TextureHandle. public TextureHandle CreateTexture(TextureHandle texture, string name, bool clear = false) { + CheckNotUsedWhenExecuting(); + var destinationDesc = GetTextureDesc(texture); destinationDesc.name = name; destinationDesc.clearBuffer = clear; @@ -774,10 +896,15 @@ namespace UnityEngine.Rendering.RenderGraphModule /// 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. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Desc used to create the texture. /// Texture from which the descriptor should be used. public void CreateTextureIfInvalid(in TextureDesc desc, ref TextureHandle texture) { + CheckNotUsedWhenExecuting(); + if (!texture.IsValid()) texture = m_Resources.CreateTexture(desc); } @@ -787,7 +914,7 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Texture resource from which the descriptor is requested. /// The input texture descriptor. - public TextureDesc GetTextureDesc(TextureHandle texture) + public TextureDesc GetTextureDesc(in TextureHandle texture) { return m_Resources.GetTextureResourceDesc(texture.handle); } @@ -804,24 +931,33 @@ namespace UnityEngine.Rendering.RenderGraphModule return info; } - /// /// Creates a new Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Renderer List descriptor. /// A new RendererListHandle. public RendererListHandle CreateRendererList(in CoreRendererListDesc desc) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateRendererList(desc); } /// /// Creates a new Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Renderer List descriptor. /// A new RendererListHandle. public RendererListHandle CreateRendererList(in RendererListParams desc) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateRendererList(desc); } @@ -838,70 +974,103 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Creates a new Gizmo Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the Gizmo. /// GizmoSubset that specifies whether gizmos render before or after postprocessing for a camera render. /// A new RendererListHandle. public RendererListHandle CreateGizmoRendererList(in Camera camera, in GizmoSubset gizmoSubset) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateGizmoRendererList(m_RenderGraphContext.renderContext, camera, gizmoSubset); } /// /// Creates a new UIOverlay Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the full UIOverlay. /// A new RendererListHandle. public RendererListHandle CreateUIOverlayRendererList(in Camera camera) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, UISubset.All); } /// /// Creates a new UIOverlay Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering some subset of the UIOverlay. /// Enum flag that specifies which subset to render. /// A new RendererListHandle. public RendererListHandle CreateUIOverlayRendererList(in Camera camera, in UISubset uiSubset) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, uiSubset); } /// /// Creates a new WireOverlay Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the WireOverlay. /// A new RendererListHandle. public RendererListHandle CreateWireOverlayRendererList(in Camera camera) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateWireOverlayRendererList(m_RenderGraphContext.renderContext, camera); } /// /// Creates a new Skybox Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the Skybox. /// A new RendererListHandle. public RendererListHandle CreateSkyboxRendererList(in Camera camera) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera); } /// /// Creates a new Skybox Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the Skybox. /// The projection matrix used during XR rendering of the skybox. /// The view matrix used during XR rendering of the skybox. /// A new RendererListHandle. public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrix, Matrix4x4 viewMatrix) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrix, viewMatrix); } /// /// Creates a new Skybox Renderer List Render Graph resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// The camera that is used for rendering the Skybox. /// The left eye projection matrix used during Legacy single pass XR rendering of the skybox. /// The left eye view matrix used during Legacy single pass XR rendering of the skybox. @@ -910,6 +1079,8 @@ namespace UnityEngine.Rendering.RenderGraphModule /// A new RendererListHandle. public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrixL, Matrix4x4 viewMatrixL, Matrix4x4 projectionMatrixR, Matrix4x4 viewMatrixR) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrixL, viewMatrixL, projectionMatrixR, viewMatrixR); } @@ -917,31 +1088,46 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Import an external Graphics Buffer to the Render Graph. /// Any pass writing to an imported graphics buffer will be considered having side effects and can't be automatically culled. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// External Graphics Buffer that needs to be imported. /// The imported graphics buffer will be released after usage. /// A new GraphicsBufferHandle. public BufferHandle ImportBuffer(GraphicsBuffer graphicsBuffer, bool forceRelease = false) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportBuffer(graphicsBuffer, forceRelease); } /// /// Create a new Render Graph Graphics Buffer resource. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Graphics Buffer descriptor. /// A new GraphicsBufferHandle. public BufferHandle CreateBuffer(in BufferDesc desc) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateBuffer(desc); } /// /// Create a new Render Graph Graphics Buffer resource using the descriptor from another graphics buffer. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// Graphics Buffer from which the descriptor should be used. /// A new GraphicsBufferHandle. public BufferHandle CreateBuffer(in BufferHandle graphicsBuffer) { + CheckNotUsedWhenExecuting(); + return m_Resources.CreateBuffer(m_Resources.GetBufferResourceDesc(graphicsBuffer.handle)); } @@ -959,17 +1145,71 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Import an external RayTracingAccelerationStructure to the Render Graph. /// Any pass writing to (building) an imported RayTracingAccelerationStructure will be considered having side effects and can't be automatically culled. /// + /// + /// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc(). + /// /// External RayTracingAccelerationStructure that needs to be imported. /// Optional name for identifying the RayTracingAccelerationStructure in the Render Graph. /// A new RayTracingAccelerationStructureHandle. public RayTracingAccelerationStructureHandle ImportRayTracingAccelerationStructure(in RayTracingAccelerationStructure accelStruct, string name = null) { + CheckNotUsedWhenExecuting(); + return m_Resources.ImportRayTracingAccelerationStructure(accelStruct, name); } + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsedWhenExecuting() + { + if (enableValidityChecks && m_RenderGraphState == RenderGraphState.Executing) + throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.Executing)); + } + + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsedWhenRecordingGraph() + { + if (enableValidityChecks && m_RenderGraphState == RenderGraphState.RecordingGraph) + throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingGraph)); + } + + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsedWhenRecordPassOrExecute() + { + if (enableValidityChecks && (m_RenderGraphState == RenderGraphState.RecordingPass || m_RenderGraphState == RenderGraphState.Executing)) + throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingPass | RenderGraphState.Executing)); + } + + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsedWhenRecordingPass() + { + if (enableValidityChecks && m_RenderGraphState == RenderGraphState.RecordingPass) + throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingPass)); + } + + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsingNativeRenderPassCompiler() + { + if (enableValidityChecks && nativeRenderPassesEnabled) + { + throw new InvalidOperationException( + "`AddRenderPass` is not compatible with the Native Render Pass Compiler. It is meant to be used with the HDRP Compiler. " + + "The APIs that are compatible with the Native Render Pass Compiler are AddUnsafePass, AddComputePass and AddRasterRenderPass."); + } + } + + [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] + void CheckNotUsedWhenActive() + { + if (enableValidityChecks && (m_RenderGraphState & RenderGraphState.Active) != RenderGraphState.Idle) + throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.Active)); + } + /// /// Add a new Raster Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute. /// + /// + /// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass(). + /// /// Type of the class to use to provide data to the Render Pass. /// Name of the new Render Pass (this is also be used to generate a GPU profiling marker). /// Instance of PassData that is passed to the render function and you must fill. @@ -1001,6 +1241,10 @@ namespace UnityEngine.Rendering.RenderGraphModule [CallerLineNumber] int line = 0) where PassData : class, new() #endif { + CheckNotUsedWhenRecordingPass(); + + m_RenderGraphState = RenderGraphState.RecordingPass; + var renderPass = m_RenderGraphPool.Get>(); renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Raster, sampler); @@ -1011,12 +1255,16 @@ namespace UnityEngine.Rendering.RenderGraphModule m_RenderPasses.Add(renderPass); m_builderInstance.Setup(renderPass, m_Resources, this); + return m_builderInstance; } /// /// Add a new Compute Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute. /// + /// + /// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass(). + /// /// Type of the class to use to provide data to the Render Pass. /// Name of the new Render Pass (this is also be used to generate a GPU profiling marker). /// Instance of PassData that is passed to the render function and you must fill. @@ -1025,8 +1273,8 @@ namespace UnityEngine.Rendering.RenderGraphModule /// A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass. public IComputeRenderGraphBuilder AddComputePass(string passName, out PassData passData #if !CORE_PACKAGE_DOCTOOLS - , [CallerFilePath] string file = "", - [CallerLineNumber] int line = 0) where PassData : class, new() + , [CallerFilePath] string file = "", + [CallerLineNumber] int line = 0) where PassData : class, new() #endif { return AddComputePass(passName, out passData, GetDefaultProfilingSampler(passName), file, line); @@ -1048,6 +1296,10 @@ namespace UnityEngine.Rendering.RenderGraphModule [CallerLineNumber] int line = 0) where PassData : class, new() #endif { + CheckNotUsedWhenRecordingPass(); + + m_RenderGraphState = RenderGraphState.RecordingPass; + var renderPass = m_RenderGraphPool.Get>(); renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Compute, sampler); @@ -1058,6 +1310,7 @@ namespace UnityEngine.Rendering.RenderGraphModule m_RenderPasses.Add(renderPass); m_builderInstance.Setup(renderPass, m_Resources, this); + return m_builderInstance; } @@ -1071,6 +1324,9 @@ namespace UnityEngine.Rendering.RenderGraphModule /// When using a unsafe pass the graph will also not automatically set up graphics state like rendertargets. The pass should do this itself /// using cmd.SetRenderTarget and related commands. /// + /// + /// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass(). + /// /// Type of the class to use to provide data to the Render Pass. /// Name of the new Render Pass (this is also be used to generate a GPU profiling marker). /// Instance of PassData that is passed to the render function and you must fill. @@ -1109,6 +1365,10 @@ namespace UnityEngine.Rendering.RenderGraphModule [CallerLineNumber] int line = 0) where PassData : class, new() #endif { + CheckNotUsedWhenRecordingPass(); + + m_RenderGraphState = RenderGraphState.RecordingPass; + var renderPass = m_RenderGraphPool.Get>(); renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Unsafe, sampler); renderPass.AllowGlobalState(true); @@ -1120,6 +1380,7 @@ namespace UnityEngine.Rendering.RenderGraphModule m_RenderPasses.Add(renderPass); m_builderInstance.Setup(renderPass, m_Resources, this); + return m_builderInstance; } @@ -1139,6 +1400,11 @@ namespace UnityEngine.Rendering.RenderGraphModule [CallerLineNumber] int line = 0) where PassData : class, new() #endif { + CheckNotUsingNativeRenderPassCompiler(); + CheckNotUsedWhenRecordingPass(); + + m_RenderGraphState = RenderGraphState.RecordingPass; + var renderPass = m_RenderGraphPool.Get>(); renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Legacy, sampler); renderPass.AllowGlobalState(true);// Old pass types allow global state by default as HDRP relies on it @@ -1155,6 +1421,9 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Add a new Render Pass to the Render Graph. /// + /// + /// This API should not be used with URP NRP Render Graph. In addition, it cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass(). + /// /// Type of the class to use to provide data to the Render Pass. /// Name of the new Render Pass (this is also be used to generate a GPU profiling marker). /// Instance of PassData that is passed to the render function and you must fill. @@ -1174,6 +1443,9 @@ namespace UnityEngine.Rendering.RenderGraphModule /// Starts the recording of the render graph. /// This must be called before adding any pass to the render graph. /// + /// + /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). + /// /// Parameters necessary for the render graph execution. /// /// Begin recording the Render Graph. @@ -1185,9 +1457,13 @@ namespace UnityEngine.Rendering.RenderGraphModule /// public void BeginRecording(in RenderGraphParameters parameters) { + CheckNotUsedWhenActive(); + + m_ExecutionExceptionWasRaised = false; + m_RenderGraphState = RenderGraphState.RecordingGraph; + m_CurrentFrameIndex = parameters.currentFrameIndex; m_CurrentExecutionName = parameters.executionName != null ? parameters.executionName : "RenderGraphExecution"; - m_HasRenderGraphBegun = true; // Cannot do renderer list culling with compilation caching because it happens after compilation is done so it can lead to discrepancies. m_RendererListCulling = parameters.rendererListCulling && !m_EnableCompilationCaching; @@ -1236,15 +1512,39 @@ namespace UnityEngine.Rendering.RenderGraphModule /// public void EndRecordingAndExecute() { + CheckNotUsedWhenRecordPassOrExecute(); + Execute(); } + /// + /// Catches and logs exceptions that could happen during the graph recording or execution. + /// + /// The exception thrown by the graph. + /// True if contexless testing is enabled, false otherwise. + public bool ResetGraphAndLogException(Exception e) + { + m_RenderGraphState = RenderGraphState.Idle; + + if (!m_RenderGraphContext.contextlessTesting) + { + // If we're not testing log the exception and swallow it. + // TODO: Do we really want to swallow exceptions here? Not a very c# thing to do. + Debug.LogError(RenderGraphExceptionMessages.k_RenderGraphExecutionError); + if (!m_ExecutionExceptionWasRaised) // Already logged. TODO: There is probably a better way in C# to handle that. + Debug.LogException(e); + m_ExecutionExceptionWasRaised = true; + } + return m_RenderGraphContext.contextlessTesting; + } + /// /// Execute the Render Graph in its current state. /// internal void Execute() { m_ExecutionExceptionWasRaised = false; + m_RenderGraphState = RenderGraphState.Executing; try { @@ -1271,7 +1571,6 @@ namespace UnityEngine.Rendering.RenderGraphModule // Feeding Render Graph Viewer before resource deallocation at pass execution GenerateDebugData(); #endif - if (nativeRenderPassesEnabled) ExecuteNativeRenderGraph(); else @@ -1283,20 +1582,8 @@ namespace UnityEngine.Rendering.RenderGraphModule } catch (Exception e) { - if (m_RenderGraphContext.contextlessTesting) - { - // Throw it for the tests to handle + if (ResetGraphAndLogException(e)) throw; - } - else - { - // If we're not testing log the exception and swallow it. - // TODO: Do we really want to swallow exceptions here? Not a very c# thing to do. - Debug.LogError("Render Graph Execution error"); - if (!m_ExecutionExceptionWasRaised) // Already logged. TODO: There is probably a better way in C# to handle that. - Debug.LogException(e); - m_ExecutionExceptionWasRaised = true; - } } finally { @@ -1309,7 +1596,7 @@ namespace UnityEngine.Rendering.RenderGraphModule InvalidateContext(); - m_HasRenderGraphBegun = false; + m_RenderGraphState = RenderGraphState.Idle; } } @@ -2374,7 +2661,7 @@ namespace UnityEngine.Rendering.RenderGraphModule { if (m_DebugParameters.enableLogging) { - m_FrameInformationLogger.LogLine($"==== Staring render graph frame for: {m_CurrentExecutionName} ===="); + m_FrameInformationLogger.LogLine($"==== Render Graph Frame Information Log ({m_CurrentExecutionName}) ===="); if (!m_DebugParameters.immediateMode) m_FrameInformationLogger.LogLine("Number of passes declared: {0}\n", m_RenderPasses.Count); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs index 039af44b..68106a2b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs @@ -315,6 +315,7 @@ namespace UnityEngine.Rendering.RenderGraphModule if (m_Disposed) return; + m_RenderGraph.RenderGraphState = RenderGraphState.RecordingGraph; m_RenderGraph.OnPassAdded(m_RenderPass); m_Disposed = true; } 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 5c1eac07..8ffd565d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs @@ -120,16 +120,18 @@ namespace UnityEngine.Rendering.RenderGraphModule try { - if (disposing) { + m_RenderGraph.RenderGraphState = RenderGraphState.RecordingGraph; + // Use all globals simply means this... we do a UseTexture on all globals so the pass has the correct dependencies. // This of course goes to show how bad an idea shader-system wide globals really are dependency/lifetime tracking wise :-) if (m_RenderPass.useAllGlobalTextures) { foreach (var texture in m_RenderGraph.AllGlobals()) { - this.UseTexture(texture, AccessFlags.Read); + if (texture.IsValid()) + this.UseTexture(texture, AccessFlags.Read); } } @@ -512,7 +514,7 @@ namespace UnityEngine.Rendering.RenderGraphModule } else { - throw new ArgumentException($"Trying to use an invalid resource (pass {m_RenderPass.name})."); + throw new Exception($"Trying to use an invalid resource (pass {m_RenderPass.name})."); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs index ea74f3d9..fb21fca2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs @@ -49,7 +49,7 @@ class RenderGraphCompilationCache where T : RenderGraph.ICompiledGraph { s_Hash = hash; - int index = hashEntries.FindIndex(0, hashEntries.size, (value) => value.hash == s_Hash); + int index = hashEntries.FindIndex(value => value.hash == s_Hash); if (index != -1) { ref var entry = ref hashEntries[index]; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs index 9bcb3d02..f3e9b8a7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs @@ -48,7 +48,16 @@ namespace UnityEngine.Rendering.RenderGraphModule m_WhiteTexture2D = RTHandles.Alloc(Texture2D.whiteTexture); if (m_ShadowTexture2D == null) - m_ShadowTexture2D = RTHandles.Alloc(1, 1, CoreUtils.GetDefaultDepthStencilFormat(), isShadowMap: true, name: "DefaultShadowTexture"); + { + m_ShadowTexture2D = RTHandles.Alloc(1, 1, CoreUtils.GetDefaultDepthOnlyFormat(), isShadowMap: true, name: "DefaultShadowTexture"); + + // Fill the shadow texture with the default (far-plane) depth value for the current platform. + CommandBuffer cmd = CommandBufferPool.Get(); + cmd.SetRenderTarget(m_ShadowTexture2D); + cmd.ClearRenderTarget(RTClearFlags.All, Color.white); + Graphics.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + } } internal void Cleanup() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphGlobalSettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphGlobalSettings.cs index 8e142638..659912db 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphGlobalSettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphGlobalSettings.cs @@ -14,7 +14,7 @@ namespace UnityEngine.Rendering /// This example demonstrates how to determine if your project uses RenderGraph's compilation caching. /// /// using UnityEngine.Rendering; - /// + /// /// public static class RenderGraphHelper /// { /// public static bool enableCompilationCaching @@ -30,8 +30,8 @@ namespace UnityEngine.Rendering /// } /// /// - [Serializable] - [SupportedOnRenderPipeline] + [Serializable] + [SupportedOnRenderPipeline] [Categorization.CategoryInfo(Name = "Render Graph", Order = 50)] [Categorization.ElementInfo(Order = 0)] public class RenderGraphGlobalSettings : IRenderPipelineGraphicsSettings diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs index 43b1c406..10bcbd8a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs @@ -77,17 +77,7 @@ namespace UnityEngine.Rendering.RenderGraphModule m_CurrentBuilder.AppendLine(); } - public string GetLog(string logName) - { - if (m_LogMap.TryGetValue(logName, out var builder)) - { - return builder.ToString(); - } - - return ""; - } - - public string GetAllLogs() + public void FlushLogs() { string result = ""; foreach (var kvp in m_LogMap) @@ -100,7 +90,7 @@ namespace UnityEngine.Rendering.RenderGraphModule m_LogMap.Clear(); - return result; + Debug.Log(result); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs index 33736468..bb920545 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs @@ -255,7 +255,7 @@ namespace UnityEngine.Rendering.RenderGraphModule { Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0); colorBufferMaxIndex = Math.Max(colorBufferMaxIndex, index); - colorBufferAccess[index].textureHandle = resource; + colorBufferAccess[index] = new TextureAccess(colorBufferAccess[index], resource); AddResourceWrite(resource.handle); } @@ -267,10 +267,7 @@ namespace UnityEngine.Rendering.RenderGraphModule if (colorBufferAccess[index].textureHandle.handle.Equals(resource.handle) || !colorBufferAccess[index].textureHandle.IsValid()) { colorBufferMaxIndex = Math.Max(colorBufferMaxIndex, index); - colorBufferAccess[index].textureHandle = resource; - colorBufferAccess[index].flags = accessFlags; - colorBufferAccess[index].mipLevel = mipLevel; - colorBufferAccess[index].depthSlice = depthSlice; + colorBufferAccess[index] = new TextureAccess(resource, accessFlags, mipLevel, depthSlice); } else { @@ -289,10 +286,7 @@ namespace UnityEngine.Rendering.RenderGraphModule if (fragmentInputAccess[index].textureHandle.handle.Equals(resource.handle) || !fragmentInputAccess[index].textureHandle.IsValid()) { fragmentInputMaxIndex = Math.Max(fragmentInputMaxIndex, index); - fragmentInputAccess[index].textureHandle = resource; - fragmentInputAccess[index].flags = accessFlags; - fragmentInputAccess[index].mipLevel = mipLevel; - fragmentInputAccess[index].depthSlice = depthSlice; + fragmentInputAccess[index] = new TextureAccess(resource, accessFlags, mipLevel, depthSlice); } else { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs index d34c6212..b5442e49 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs @@ -13,7 +13,7 @@ namespace UnityEngine.Rendering.RenderGraphModule /// /// Basic properties of a RTHandle needed by the render graph compiler. It is not always possible to derive these /// given an RTHandle so the user needs to pass these in. - /// + /// /// We don't use a full RenderTargetDescriptor here as filling out a full descriptor may not be trivial for users and not all /// members of the descriptor are actually used by the render graph. This struct is the minimum set of info needed by the render graph. /// If you want to develop some utility framework to work with render textures, etc. it's probably better to use RenderTargetDescriptor. @@ -91,7 +91,7 @@ namespace UnityEngine.Rendering.RenderGraphModule m_CurrentRegistry = value; } } - + delegate bool ResourceCreateCallback(InternalRenderGraphContext rgContext, IRenderGraphResource res); delegate void ResourceCallback(InternalRenderGraphContext rgContext, IRenderGraphResource res); @@ -550,12 +550,12 @@ namespace UnityEngine.Rendering.RenderGraphModule // Store the info in the descriptor structure to avoid having a separate info structure being saved per resource // This descriptor will then be used to reconstruct the info (see GetRenderTargetInfo) but is not a full featured descriptor. // This is ok as this descriptor will never be used to create textures (as they are imported into the graph and thus externally created). - + texResource.desc.format = info.format; texResource.desc.width = info.width; texResource.desc.height = info.height; texResource.desc.slices = info.volumeDepth; - texResource.desc.msaaSamples = (MSAASamples)info.msaaSamples; + texResource.desc.msaaSamples = (MSAASamples)info.msaaSamples; texResource.desc.bindTextureMS = info.bindMS; texResource.desc.clearBuffer = importParams.clearOnFirstUse; texResource.desc.clearColor = importParams.clearColor; @@ -760,9 +760,8 @@ namespace UnityEngine.Rendering.RenderGraphModule // screen resolution,.... we can't even hope to know or replicate the size calculation here // so we just say we don't know what this rt is and rely on the user passing in the info to us. var desc = GetTextureResourceDesc(res, true); - outInfo = new RenderTargetInfo(); #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (desc.width == 0 || desc.height == 0 || desc.slices == 0 || desc.msaaSamples == 0 || desc.format == GraphicsFormat.None) + if (desc.width == 0 || desc.height == 0 || desc.slices == 0 || desc.msaaSamples == 0 || desc.format == GraphicsFormat.None) { throw new Exception("Invalid imported texture. A RTHandle wrapping an RenderTargetIdentifier was imported without providing valid RenderTargetInfo."); } @@ -792,13 +791,13 @@ namespace UnityEngine.Rendering.RenderGraphModule outInfo.msaaSamples = (int)desc.msaaSamples; outInfo.bindMS = desc.bindTextureMS; - outInfo.format = desc.format; + outInfo.format = desc.format; } } internal GraphicsFormat GetFormat(GraphicsFormat color, GraphicsFormat depthStencil) { - ValidateFormat(color, depthStencil); + ValidateFormat(color, depthStencil); return (depthStencil != GraphicsFormat.None) ? depthStencil : color; } @@ -1067,17 +1066,35 @@ namespace UnityEngine.Rendering.RenderGraphModule #endif bool executedWork = false; + if ((forceManualClearOfResource && resource.desc.clearBuffer) || m_RenderGraphDebug.clearRenderTargetsAtCreation) { - bool debugClear = m_RenderGraphDebug.clearRenderTargetsAtCreation && !resource.desc.clearBuffer; - var clearFlag = GraphicsFormatUtility.IsDepthStencilFormat(resource.desc.format) ? ClearFlag.DepthStencil : ClearFlag.Color; - var clearColor = debugClear ? Color.magenta : resource.desc.clearColor; - CoreUtils.SetRenderTarget(rgContext.cmd, resource.graphicsResource, clearFlag, clearColor); + ClearTexture(rgContext, resource); executedWork = true; } return executedWork; } + internal void ClearResource(InternalRenderGraphContext rgContext, int type, int index) + { + var resource = m_RenderGraphResources[type].resourceArray[index]; + + // Only TextureResource for now, but we expect to want to handle other types of resources in the future + if (resource is TextureResource textureResource) + { + ClearTexture(rgContext, textureResource); + } + } + + private void ClearTexture(InternalRenderGraphContext rgContext, TextureResource resource) + { + if (resource == null) return; + var debugClear = m_RenderGraphDebug.clearRenderTargetsAtCreation && !resource.desc.clearBuffer; + var clearFlag = GraphicsFormatUtility.IsDepthStencilFormat(resource.desc.format) ? ClearFlag.DepthStencil : ClearFlag.Color; + var clearColor = debugClear ? Color.magenta : resource.desc.clearColor; + CoreUtils.SetRenderTarget(rgContext.cmd, resource.graphicsResource, clearFlag, clearColor); + } + internal void ReleasePooledResource(InternalRenderGraphContext rgContext, int type, int index) { var resource = m_RenderGraphResources[type].resourceArray[index]; @@ -1140,7 +1157,7 @@ namespace UnityEngine.Rendering.RenderGraphModule } } - // Bind ms textures need to use the ms texture sampling functions so there is no "silent" fallback or interoperability between a "non-ms texture" and an "ms texture which happens to have 1 sample" + // Bind ms textures need to use the ms texture sampling functions so there is no "silent" fallback or interoperability between a "non-ms texture" and an "ms texture which happens to have 1 sample" // it's either ms with > 1 sample or "normal texture". This is unlike array textures where you can have an array with 1 slice. if ((int)desc.msaaSamples <= 1 && desc.bindTextureMS == true) { @@ -1251,16 +1268,11 @@ namespace UnityEngine.Rendering.RenderGraphModule RTHandles.Release(m_CurrentBackbuffer); } - internal void FlushLogs() - { - Debug.Log(m_ResourceLogger.GetAllLogs()); - } - void LogResources() { if (m_RenderGraphDebug.enableLogging) { - m_ResourceLogger.LogLine("==== Allocated Resources ====\n"); + m_ResourceLogger.LogLine("==== Render Graph Resource Log ====\n"); for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type) { @@ -1273,6 +1285,11 @@ namespace UnityEngine.Rendering.RenderGraphModule } } + internal void FlushLogs() + { + m_ResourceLogger.FlushLogs(); + } + #endregion } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs index f92ae931..12f42771 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs @@ -7,12 +7,12 @@ using UnityEngine.Scripting.APIUpdating; namespace UnityEngine.Rendering.RenderGraphModule { - internal struct TextureAccess + internal readonly struct TextureAccess { - public TextureHandle textureHandle; - public int mipLevel; - public int depthSlice; - public AccessFlags flags; + public readonly TextureHandle textureHandle; + public readonly int mipLevel; + public readonly int depthSlice; + public readonly AccessFlags flags; public TextureAccess(TextureHandle handle, AccessFlags flags, int mipLevel, int depthSlice) { @@ -21,6 +21,14 @@ namespace UnityEngine.Rendering.RenderGraphModule this.mipLevel = mipLevel; this.depthSlice = depthSlice; } + + public TextureAccess(TextureAccess access, TextureHandle handle) + { + this.textureHandle = handle; + this.flags = access.flags; + this.mipLevel = access.mipLevel; + this.depthSlice = access.depthSlice; + } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Settings/LightmapSamplingSettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/Settings/LightmapSamplingSettings.cs index d6ff46e1..87b1975e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Settings/LightmapSamplingSettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Settings/LightmapSamplingSettings.cs @@ -15,6 +15,8 @@ namespace UnityEngine.Rendering int IRenderPipelineGraphicsSettings.version { get => m_Version; } + bool IRenderPipelineGraphicsSettings.isAvailableInPlayerBuild => true; + [SerializeField, Tooltip("Use Bicubic Lightmap Sampling. Enabling this will improve the appearance of lightmaps, but may worsen performance on lower end platforms.")] bool m_UseBicubicLightmapSampling; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs new file mode 100644 index 00000000..cc7c00f2 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs @@ -0,0 +1,24 @@ +using System; + +namespace UnityEngine.Rendering +{ + [Serializable, HideInInspector] + [SupportedOnRenderPipeline] + [Categorization.CategoryInfo(Name = "R : Rendering Debugger Resources", Order = 100)] + [Categorization.ElementInfo(Order = 0)] + class RenderingDebuggerRuntimeResources : IRenderPipelineResources + { + enum Version + { + Initial, + + Count, + Last = Count - 1 + } + [SerializeField, HideInInspector] + private Version m_version = Version.Last; + int IRenderPipelineGraphicsSettings.version => (int)m_version; + + // TODO Add Rendering Debugger Resources here + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs.meta new file mode 100644 index 00000000..c346610f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Settings/RenderingDebuggerRuntimeResources.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c8ecfef0ec5856a4fa9b1c416f2d51e3 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs index 9c82d161..eb87426b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs @@ -99,7 +99,9 @@ namespace UnityEngine.Rendering /// Game Object Menu priority public const int gameObjectMenuPriority = 10; /// Lens Flare Priority - public const int srpLensFlareMenuPriority = 303; + public const int srpLensFlareMenuPriority = 9; + /// Scripting Priority + public const int scriptingPriority = 40; } const string obsoletePriorityMessage = "Use CoreUtils.Priorities instead"; @@ -994,7 +996,7 @@ namespace UnityEngine.Rendering temp = string.Format("{0}x{1}{2}_{3}", width, height, mips ? "_Mips" : "", format); else temp = string.Format("{0}x{1}x{2}{3}_{4}", width, height, depth, mips ? "_Mips" : "", format); - temp = String.Format("{0}_{1}_{2}", name == "" ? "Texture" : name, (dim == TextureDimension.None) ? "" : dim.ToString(), temp); + temp = String.Format("{0}_{1}_{2}", name?.Length == 0 ? "Texture" : name, (dim == TextureDimension.None) ? "" : dim.ToString(), temp); return temp; } @@ -1851,6 +1853,20 @@ namespace UnityEngine.Rendering #endif } + /// + /// Return the GraphicsFormat of Depth-only RenderTarget preferred for the current platform. + /// + /// The GraphicsFormat of Depth-only RenderTarget preferred for the current platform. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static GraphicsFormat GetDefaultDepthOnlyFormat() + { +#if UNITY_SWITCH || UNITY_EMBEDDED_LINUX || UNITY_QNX || UNITY_ANDROID + return GraphicsFormatUtility.GetDepthStencilFormat(24, 0); // returns GraphicsFormat.D24_UNorm when hardware supports it +#else + return GraphicsFormat.D32_SFloat; +#endif + } + /// /// Return the number of DepthStencil RenderTarget depth bits preferred for the current platform. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/Volume.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/Volume.cs index 82ff5a11..ebb8a8e1 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/Volume.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/Volume.cs @@ -7,7 +7,8 @@ namespace UnityEngine.Rendering /// /// A generic Volume component holding a . /// - [CurrentPipelineHelpURL("Volumes")] + [PipelineHelpURL("HDRenderPipelineAsset","understand-volumes")] + [PipelineHelpURL("UniversalRenderPipelineAsset", "Volumes")] [ExecuteAlways] [AddComponentMenu("Miscellaneous/Volume")] public class Volume : MonoBehaviour, IVolume @@ -21,25 +22,31 @@ namespace UnityEngine.Rendering public bool isGlobal { get => m_IsGlobal; - set => m_IsGlobal = value; + set + { + m_IsGlobal = value; + if (!m_IsGlobal) + UpdateColliders(); + } } /// /// A value which determines which Volume is being used when Volumes have an equal amount of influence on the Scene. Volumes with a higher priority will override lower ones. /// - [Delayed] + [Delayed, FormerlySerializedAs("m_Priority")] public float priority = 0f; /// /// The outer distance to start blending from. A value of 0 means no blending and Unity applies /// the Volume overrides immediately upon entry. /// + [FormerlySerializedAs("m_BlendDistance")] public float blendDistance = 0f; /// /// The total weight of this volume in the Scene. 0 means no effect and 1 means full effect. /// - [Range(0f, 1f)] + [Range(0f, 1f), FormerlySerializedAs("m_Weight")] public float weight = 1f; /// @@ -91,12 +98,15 @@ namespace UnityEngine.Rendering set => m_InternalProfile = value; } - internal List m_Colliders = new List(); + readonly List m_Colliders = new List(); /// /// The colliders of the volume if is false /// public List colliders => m_Colliders; + + GameObject m_CachedGameObject; + internal GameObject cachedGameObject => m_CachedGameObject; internal VolumeProfile profileRef => m_InternalProfile == null ? sharedProfile : m_InternalProfile; @@ -115,9 +125,10 @@ namespace UnityEngine.Rendering void OnEnable() { - m_PreviousLayer = gameObject.layer; + m_CachedGameObject = gameObject; + m_PreviousLayer = cachedGameObject.layer; VolumeManager.instance.Register(this); - GetComponents(m_Colliders); + UpdateColliders(); } void OnDisable() @@ -132,10 +143,22 @@ namespace UnityEngine.Rendering #if UNITY_EDITOR // In the editor, we refresh the list of colliders at every frame because it's frequent to add/remove them - GetComponents(m_Colliders); + UpdateColliders(); #endif } + /// + /// Updates the cached list of colliders stored in the Volume. + /// + /// + /// The Volume class caches a list of colliders for performance and quick access. + /// If you add or remove colliders at runtime, call this method to refresh the cached collider list. + /// + public void UpdateColliders() + { + GetComponents(m_Colliders); + } + internal void UpdateLayer() { // Unfortunately we need to track the current layer to update the volume manager in @@ -143,7 +166,7 @@ namespace UnityEngine.Rendering // Because no event is raised when the layer changes, we have to track it on every // frame :/ - int layer = gameObject.layer; + int layer = cachedGameObject.layer; if (layer == m_PreviousLayer) return; @@ -153,14 +176,14 @@ namespace UnityEngine.Rendering internal void UpdatePriority() { - if (!(Math.Abs(priority - m_PreviousPriority) > Mathf.Epsilon)) + if (!(Mathf.Abs(priority - m_PreviousPriority) > Mathf.Epsilon)) return; // Same for priority. We could use a property instead, but it doesn't play nice with the // serialization system. Using a custom Attribute/PropertyDrawer for a property is // possible but it doesn't work with Undo/Redo in the editor, which makes it useless for // our case. - VolumeManager.instance.SetLayerDirty(gameObject.layer); + VolumeManager.instance.SetLayerDirty(cachedGameObject.layer); m_PreviousPriority = priority; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs index 3f2bf8b9..4fa42010 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs @@ -162,21 +162,13 @@ namespace UnityEngine.Rendering /// /// The backing storage of . Use this for performance-critical work. /// - internal readonly List parameterList = new(); - + internal VolumeParameter[] parameterList; + ReadOnlyCollection m_ParameterReadOnlyCollection; /// /// A read-only collection of all the s defined in this class. /// - public ReadOnlyCollection parameters - { - get - { - if (m_ParameterReadOnlyCollection == null) - m_ParameterReadOnlyCollection = parameterList.AsReadOnly(); - return m_ParameterReadOnlyCollection; - } - } + public ReadOnlyCollection parameters => m_ParameterReadOnlyCollection ??= new ReadOnlyCollection(parameterList); /// /// Extracts all the s defined in this class and nested classes. @@ -195,7 +187,8 @@ namespace UnityEngine.Rendering foreach (var field in fields) { - if (field.FieldType.IsSubclassOf(typeof(VolumeParameter))) + var fieldType = field.FieldType; + if (fieldType.IsSubclassOf(typeof(VolumeParameter))) { if (filter?.Invoke(field) ?? true) { @@ -206,7 +199,7 @@ namespace UnityEngine.Rendering parameters.Add(volumeParameter); } } - else if (!field.FieldType.IsArray && field.FieldType.IsClass) + else if (!fieldType.IsArray && fieldType.IsClass) FindParameters(field.GetValue(o), parameters, filter); } } @@ -220,8 +213,10 @@ namespace UnityEngine.Rendering protected virtual void OnEnable() { // Automatically grab all fields of type VolumeParameter for this instance - parameterList.Clear(); - FindParameters(this, parameterList); + ListPool.Get(out var tempList); + FindParameters(this, tempList); + parameterList = tempList.ToArray(); + ListPool.Release(tempList); foreach (var parameter in parameterList) { @@ -282,7 +277,7 @@ namespace UnityEngine.Rendering /// public virtual void Override(VolumeComponent state, float interpFactor) { - int count = parameterList.Count; + int count = parameterList.Length; for (int i = 0; i < count; i++) { @@ -343,7 +338,7 @@ namespace UnityEngine.Rendering int hash = 17; - for (int i = 0; i < parameterList.Count; i++) + for (int i = 0; i < parameterList.Length; i++) hash = hash * 23 + parameterList[i].GetHashCode(); return hash; @@ -356,9 +351,10 @@ namespace UnityEngine.Rendering /// True if any of the volume properites has been overridden. public bool AnyPropertiesIsOverridden() { - for (int i = 0; i < parameterList.Count; ++i) + for (int i = 0; i < parameterList.Length; ++i) { - if (parameterList[i].overrideState) return true; + if (parameterList[i].overrideState) + return true; } return false; } @@ -376,7 +372,7 @@ namespace UnityEngine.Rendering if (parameterList == null) return; - for (int i = 0; i < parameterList.Count; i++) + for (int i = 0; i < parameterList.Length; i++) { if (parameterList[i] != null) parameterList[i].Release(); 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 d007439e..3909ce32 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs @@ -216,9 +216,6 @@ namespace UnityEngine.Rendering return null; } - // Recycled list used for volume traversal - readonly List m_TempColliders = new(8); - // The default stack the volume manager uses. // We cache this as users able to change the stack through code and // we want to be able to switch to the default one through the ResetMainStack() function. @@ -581,9 +578,17 @@ namespace UnityEngine.Rendering m_VolumeCollection.ChangeLayer(volume, prevLayer, newLayer); } +#if UNITY_EDITOR || DEVELOPMENT_BUILD + internal bool renderingDebuggerAttached { get; set; } + internal event Action beginVolumeStackUpdate; + internal event Action endVolumeStackUpdate; + internal event Action overrideVolumeStackData; +#endif + // Go through all listed components and lerp overridden values in the global state - void OverrideData(VolumeStack stack, List components, float interpFactor) + void OverrideData(VolumeStack stack, Volume volume, float interpFactor) { + var components = volume.profileRef.components; var numComponents = components.Count; for (int i = 0; i < numComponents; i++) { @@ -597,6 +602,12 @@ namespace UnityEngine.Rendering component.Override(state, interpFactor); } } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (renderingDebuggerAttached) + overrideVolumeStackData?.Invoke(stack, volume, interpFactor); +#endif + } // Faster version of OverrideData to force replace values in the global state. @@ -733,6 +744,11 @@ namespace UnityEngine.Rendering if (!onlyGlobal) trigger.TryGetComponent(out camera); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (renderingDebuggerAttached) + beginVolumeStackUpdate?.Invoke(stack, camera); +#endif + // Traverse all volumes int numVolumes = volumes.Count; for (int i = 0; i < numVolumes; i++) @@ -754,7 +770,7 @@ namespace UnityEngine.Rendering // Global volumes always have influence if (volume.isGlobal) { - OverrideData(stack, volume.profileRef.components, Mathf.Clamp01(volume.weight)); + OverrideData(stack, volume, Mathf.Clamp01(volume.weight)); continue; } @@ -762,15 +778,13 @@ namespace UnityEngine.Rendering continue; // If volume isn't global and has no collider, skip it as it's useless - var colliders = m_TempColliders; - volume.GetComponents(colliders); - if (colliders.Count == 0) + var colliders = volume.colliders; + int numColliders = colliders.Count; + if (numColliders == 0) continue; // Find closest distance to volume, 0 means it's inside it float closestDistanceSqr = float.PositiveInfinity; - - int numColliders = colliders.Count; for (int c = 0; c < numColliders; c++) { var collider = colliders[c]; @@ -784,7 +798,6 @@ namespace UnityEngine.Rendering closestDistanceSqr = d; } - colliders.Clear(); float blendDistSqr = volume.blendDistance * volume.blendDistance; // Volume has no influence, ignore it @@ -800,9 +813,14 @@ namespace UnityEngine.Rendering if (blendDistSqr > 0f) interpFactor = 1f - (closestDistanceSqr / blendDistSqr); - // No need to clamp01 the interpolation factor as it'll always be in [0;1[ range - OverrideData(stack, volume.profileRef.components, interpFactor * Mathf.Clamp01(volume.weight)); + // No need to clamp01 the interpolation factor or weight as both are always in [0;1[ range + OverrideData(stack, volume, interpFactor * Mathf.Clamp01(volume.weight)); } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (renderingDebuggerAttached) + endVolumeStackUpdate?.Invoke(stack, camera); +#endif } /// @@ -826,10 +844,10 @@ namespace UnityEngine.Rendering { #if UNITY_2018_3_OR_NEWER && UNITY_EDITOR // GameObject for default global volume may not belong to any scene, following check prevents it from being culled - if (!volume.gameObject.scene.IsValid()) + if (!volume.cachedGameObject.scene.IsValid()) return true; // IsGameObjectRenderedByCamera does not behave correctly when camera is null so we have to catch it here. - return camera == null ? true : UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(volume.gameObject, camera); + return camera == null || UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(volume.cachedGameObject, camera); #else return true; #endif diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs index 7c44195f..51a2e011 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs @@ -32,7 +32,6 @@ namespace UnityEngine.Rendering #if UNITY_EDITOR || DEVELOPMENT_BUILD internal int fieldHash { get; set; } #endif - /// /// A beautified string for debugger output. This is set on a DebuggerDisplay on every /// parameter types. @@ -278,7 +277,7 @@ namespace UnityEngine.Rendering /// The first value in a . /// The second value. /// true if both values are equal, false otherwise. - public static bool operator ==(VolumeParameter lhs, T rhs) => lhs != null && !ReferenceEquals(lhs.value, null) && lhs.value.Equals(rhs); + public static bool operator ==(VolumeParameter lhs, T rhs) => !ReferenceEquals(lhs, null) && !ReferenceEquals(lhs.value, null) && lhs.value.Equals(rhs); /// /// Compares the value store in a parameter with another value of the same type. @@ -311,16 +310,7 @@ namespace UnityEngine.Rendering /// true if the specified object is equal to the current object, false otherwise. public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) - return false; - - if (ReferenceEquals(this, obj)) - return true; - - if (obj.GetType() != GetType()) - return false; - - return Equals((VolumeParameter)obj); + return Equals(obj as VolumeParameter); } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeProfile.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeProfile.cs index 60803deb..6b15949c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeProfile.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeProfile.cs @@ -8,7 +8,8 @@ namespace UnityEngine.Rendering /// /// An Asset which holds a set of settings to use with a . /// - [CurrentPipelineHelpURL("Volume-Profile")] + [PipelineHelpURL("UniversalRenderPipelineAsset","Volume-Profile")] + [PipelineHelpURL("HDRenderPipelineAsset","create-a-volume-profile")] [Icon("Packages/com.unity.render-pipelines.core/Editor/Icons/Processed/VolumeProfile Icon.asset")] public sealed class VolumeProfile : ScriptableObject { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRGraphicsAutomatedTests.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRGraphicsAutomatedTests.cs index b1c64f65..aa518d97 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRGraphicsAutomatedTests.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRGraphicsAutomatedTests.cs @@ -74,7 +74,7 @@ namespace UnityEngine.Rendering viewMatrix *= Matrix4x4.Translate(new Vector3(.34f, 0.25f, -0.08f)); } - XRView xrView = new XRView(projMatrix, viewMatrix, Matrix4x4.identity, false, xrPass.GetViewport(viewId), null, xrPass.GetTextureArraySlice(viewId)); + XRView xrView = new XRView(projMatrix, viewMatrix, Matrix4x4.identity, false, xrPass.GetViewport(viewId), null, null, xrPass.GetTextureArraySlice(viewId)); xrPass.AssignView(viewId, xrView); } } 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 22cc9761..28a33a56 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRPass.cs @@ -41,6 +41,7 @@ namespace UnityEngine.Experimental.Rendering { readonly List m_Views; readonly XROcclusionMesh m_OcclusionMesh; + readonly XRVisibleMesh m_VisibleMesh; /// /// Parameterless constructor. @@ -50,6 +51,7 @@ namespace UnityEngine.Experimental.Rendering { m_Views = new List(2); m_OcclusionMesh = new XROcclusionMesh(this); + m_VisibleMesh = new XRVisibleMesh(this); } /// @@ -69,6 +71,7 @@ namespace UnityEngine.Experimental.Rendering /// virtual public void Release() { + m_VisibleMesh.Dispose(); GenericPool.Release(this); } @@ -301,6 +304,16 @@ namespace UnityEngine.Experimental.Rendering return m_Views[viewIndex].occlusionMesh; } + /// + /// Returns the visible mesh for a given view. + /// + /// Index of XRView to retrieve the data from. + /// XR visible mesh for the specified XRView. + public Mesh GetVisibleMesh(int viewIndex = 0) + { + return m_Views[viewIndex].visibleMesh; + } + /// /// Returns the destination slice index (for texture array) for a given view. /// @@ -389,6 +402,11 @@ namespace UnityEngine.Experimental.Rendering /// public bool hasValidOcclusionMesh { get => m_OcclusionMesh.hasValidOcclusionMesh; } + /// + /// Returns true if the pass was setup with expected mesh and enabled by settings. + /// + public bool hasValidVisibleMesh { get => m_VisibleMesh.hasValidVisibleMesh && XRSystem.GetUseVisibilityMesh(); } + /// /// Generate commands to render the occlusion mesh for this pass. /// In single-pass mode : the meshes for all views are combined into one mesh, @@ -417,6 +435,44 @@ namespace UnityEngine.Experimental.Rendering m_OcclusionMesh.RenderOcclusionMesh(cmd.m_WrappedCommandBuffer, occlusionMeshScale, renderIntoTexture); } + /// + /// Generate commands to render the visible mesh for this pass using a custom material and set of material property block. + /// In single-pass mode : the meshes for all views are combined into one mesh, + /// where the corresponding view index is encoded into each vertex. + /// + /// RasterCommandBuffer to modify + /// Occlusion Mesh scale + /// Material that the visibility mesh will render. + /// Material block with all the shader parameters that need to be set. + /// Material shader pass to render, set 0 by default. + /// Set to true when rendering into a render texture. Used for handling Unity yflip. + public void RenderVisibleMeshCustomMaterial(RasterCommandBuffer cmd, float occlusionMeshScale, + Material material, MaterialPropertyBlock materialBlock, int shaderPass, bool renderIntoTexture = false) + { + if (occlusionMeshScale > 0) + m_VisibleMesh.RenderVisibleMeshCustomMaterial(cmd.m_WrappedCommandBuffer, occlusionMeshScale, material, materialBlock, shaderPass, renderIntoTexture); + + } + + /// + /// Generate commands to render the visible mesh for this pass using a custom material and set of material property block. + /// In single-pass mode : the meshes for all views are combined into one mesh, + /// where the corresponding view index is encoded into each vertex. + /// + /// RasterCommandBuffer to modify + /// Occlusion Mesh scale + /// Material that the visibility mesh will render. + /// Material block with all the shader parameters that need to be set. + /// Material shader pass to render, set 0 by default. + /// Set to true when rendering into a render texture. Used for handling Unity yflip. + public void RenderVisibleMeshCustomMaterial(CommandBuffer cmd, float occlusionMeshScale, + Material material, MaterialPropertyBlock materialBlock, int shaderPass = 0, bool renderIntoTexture = false) + { + if (occlusionMeshScale > 0) + m_VisibleMesh.RenderVisibleMeshCustomMaterial(cmd, occlusionMeshScale, material, materialBlock, shaderPass, renderIntoTexture); + + } + /// /// Draw debug line for all XR views. /// @@ -478,6 +534,7 @@ namespace UnityEngine.Experimental.Rendering internal void UpdateCombinedOcclusionMesh() { m_OcclusionMesh.UpdateCombinedMesh(); + m_VisibleMesh.UpdateCombinedMesh(); } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSRPSettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSRPSettings.cs index bb519251..9b58d551 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSRPSettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSRPSettings.cs @@ -155,6 +155,28 @@ namespace UnityEngine.Rendering } } + /// + /// Controls the use of the Visibility Mesh passes in SRP. + /// + public static bool useVisibilityMesh + { + get + { +#if ENABLE_VR && ENABLE_VR_MODULE + if (enabled) + return XRSystem.GetUseVisibilityMesh(); +#endif + return false; + } + set + { +#if ENABLE_VR && ENABLE_VR_MODULE + if (enabled) + XRSystem.SetUseVisibilityMesh(value); +#endif + } + } + /// /// Controls XR mirror view blit operation /// 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 62f25ce4..582999e9 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs @@ -49,6 +49,9 @@ namespace UnityEngine.Experimental.Rendering #if ENABLE_VR && ENABLE_XR_MODULE // Occlusion Mesh scaling factor static float s_OcclusionMeshScaling = 1.0f; + + // Return true if wants to enable visibility mesh passes + static bool s_UseVisibilityMesh = true; #endif // Internal resources used by XR rendering @@ -183,6 +186,29 @@ namespace UnityEngine.Experimental.Rendering #endif } + /// + /// Used by the render pipeline to enable all visibility meshes passes. + /// + /// True to enable visibility mesh passes, false to disable them. + internal static void SetUseVisibilityMesh(bool useVisibilityMesh) + { +#if ENABLE_VR && ENABLE_XR_MODULE + s_UseVisibilityMesh = useVisibilityMesh; +#endif + } + + /// + /// Returned value used by the render pipeline to use all visibility mesh passes. + /// + internal static bool GetUseVisibilityMesh() + { +#if ENABLE_VR && ENABLE_XR_MODULE + return s_UseVisibilityMesh; +#else + return false; +#endif + } + /// /// Used to communicate to the XR device how to render the XR MirrorView. Note: not all blit modes are supported by all providers. Blitmode set here serves as preference purpose. /// @@ -497,8 +523,9 @@ namespace UnityEngine.Experimental.Rendering // XRTODO : remove this line and use XRSettings.useOcclusionMesh instead when it's fixed Mesh occlusionMesh = XRGraphicsAutomatedTests.running ? null : renderParameter.occlusionMesh; + Mesh visibleMesh = XRGraphicsAutomatedTests.running ? null : renderParameter.visibleMesh; - return new XRView(renderParameter.projection, renderParameter.view, renderParameter.previousView, renderParameter.isPreviousViewValid, viewport, occlusionMesh, renderParameter.textureArraySlice); + return new XRView(renderParameter.projection, renderParameter.view, renderParameter.previousView, renderParameter.isPreviousViewValid, viewport, occlusionMesh, visibleMesh, renderParameter.textureArraySlice); } private static RenderTextureDescriptor XrRenderTextureDescToUnityRenderTextureDesc(RenderTextureDescriptor xrDesc) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRView.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRView.cs index 71803ba1..bb94d29d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRView.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRView.cs @@ -9,17 +9,19 @@ namespace UnityEngine.Experimental.Rendering internal readonly Matrix4x4 prevViewMatrix; internal readonly Rect viewport; internal readonly Mesh occlusionMesh; + internal readonly Mesh visibleMesh; internal readonly int textureArraySlice; internal readonly Vector2 eyeCenterUV; internal readonly bool isPrevViewMatrixValid; - internal XRView(Matrix4x4 projMatrix, Matrix4x4 viewMatrix, Matrix4x4 prevViewMatrix, bool isPrevViewMatrixValid, Rect viewport, Mesh occlusionMesh, int textureArraySlice) + internal XRView(Matrix4x4 projMatrix, Matrix4x4 viewMatrix, Matrix4x4 prevViewMatrix, bool isPrevViewMatrixValid, Rect viewport, Mesh occlusionMesh, Mesh visibleMesh, int textureArraySlice) { this.projMatrix = projMatrix; this.viewMatrix = viewMatrix; this.prevViewMatrix = prevViewMatrix; this.viewport = viewport; this.occlusionMesh = occlusionMesh; + this.visibleMesh = visibleMesh; this.textureArraySlice = textureArraySlice; this.isPrevViewMatrixValid = isPrevViewMatrixValid; eyeCenterUV = ComputeEyeCenterUV(projMatrix); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs new file mode 100644 index 00000000..b15b40fc --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs @@ -0,0 +1,162 @@ +using UnityEngine.Rendering; + +namespace UnityEngine.Experimental.Rendering +{ + // Helper class to render the visible mesh using custom materials. + // If possible, the mesh for each view will be combined into one mesh to reduce draw calls. + internal class XRVisibleMesh + { + XRPass m_Pass; + Mesh m_CombinedMesh; + int m_CombinedMeshHashCode; + + static readonly ProfilingSampler k_VisibleMeshProfilingSampler = new ProfilingSampler("XR Visible Mesh"); + + internal XRVisibleMesh(XRPass xrPass) + { + m_Pass = xrPass; + } + + internal void Dispose() + { + if (m_CombinedMesh) + { + CoreUtils.Destroy(m_CombinedMesh); + m_CombinedMesh = null; + } + } + + internal bool hasValidVisibleMesh + { + get + { + if (IsVisibleMeshSupported()) + { + if (m_Pass.singlePassEnabled) + return m_CombinedMesh != null; + else + return m_Pass.GetVisibleMesh() != null; + } + + return false; + } + } + + internal void RenderVisibleMeshCustomMaterial(CommandBuffer cmd, float occlusionMeshScale, Material material, MaterialPropertyBlock materialBlock, int shaderPass, bool yFlip = false) + { + if (IsVisibleMeshSupported()) + { + using (new ProfilingScope(cmd, k_VisibleMeshProfilingSampler)) + { + Vector3 scale = new Vector3(occlusionMeshScale, yFlip ? occlusionMeshScale : -occlusionMeshScale, 1.0f); + Mesh VisMesh = m_Pass.singlePassEnabled ? m_CombinedMesh : m_Pass.GetVisibleMesh(0); + cmd.DrawMesh(VisMesh, Matrix4x4.Scale(scale), material, 0, shaderPass, materialBlock); + } + } + } + + internal void UpdateCombinedMesh() + { + if (IsVisibleMeshSupported() && m_Pass.singlePassEnabled && TryGetVisibleMeshCombinedHashCode(out var hashCode)) + { + if (m_CombinedMesh == null || hashCode != m_CombinedMeshHashCode) + { + CreateVisibleMeshCombined(); + m_CombinedMeshHashCode = hashCode; + } + } + else + { + m_CombinedMesh = null; + m_CombinedMeshHashCode = 0; + } + } + + bool IsVisibleMeshSupported() + { + return m_Pass.enabled && m_Pass.occlusionMeshScale > 0.0f; + } + + bool TryGetVisibleMeshCombinedHashCode(out int hashCode) + { + hashCode = 17; + + for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId) + { + Mesh mesh = m_Pass.GetVisibleMesh(viewId); + + if (mesh != null) + { + hashCode = hashCode * 23 + mesh.GetHashCode(); + } + else + { + hashCode = 0; + return false; + } + } + + return true; + } + + // Create a new mesh that contains the visible data from all views + // This essentially fetches the mesh vertices from XRPass.GetVisibleMesh(viewId=0,1) + // and combines them into one mesh. + void CreateVisibleMeshCombined() + { + CoreUtils.Destroy(m_CombinedMesh); + + m_CombinedMesh = new Mesh(); + m_CombinedMesh.indexFormat = IndexFormat.UInt16; + + int combinedVertexCount = 0; + uint combinedIndexCount = 0; + + for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId) + { + Mesh mesh = m_Pass.GetVisibleMesh(viewId); + + Debug.Assert(mesh != null); + Debug.Assert(mesh.subMeshCount == 1); + Debug.Assert(mesh.indexFormat == IndexFormat.UInt16); + + combinedVertexCount += mesh.vertexCount; + combinedIndexCount += mesh.GetIndexCount(0); + } + + Vector3[] vertices = new Vector3[combinedVertexCount]; + ushort[] indices = new ushort[combinedIndexCount]; + int vertexStart = 0; + int indexStart = 0; + + for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId) + { + Mesh mesh = m_Pass.GetVisibleMesh(viewId); + var meshIndices = mesh.GetIndices(0); + + // Encode the viewId into the z channel + { + mesh.vertices.CopyTo(vertices, vertexStart); + + for (int i = 0; i < mesh.vertices.Length; i++) + vertices[vertexStart + i].z = viewId; + } + + // Combine indices into one buffer + for (int i = 0; i < meshIndices.Length; i++) + { + int newIndex = vertexStart + meshIndices[i]; + Debug.Assert(meshIndices[i] < ushort.MaxValue); + + indices[indexStart + i] = (ushort)newIndex; + } + + vertexStart += mesh.vertexCount; + indexStart += meshIndices.Length; + } + + m_CombinedMesh.vertices = vertices; + m_CombinedMesh.SetIndices(indices, MeshTopology.Triangles, 0); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs.meta new file mode 100644 index 00000000..7c6e6b55 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRVisibleMesh.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7fd1ba8431960304588429bd8a60e2df \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLCore.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLCore.hlsl index 0bac51c3..6aceffba 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLCore.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLCore.hlsl @@ -60,17 +60,15 @@ #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) -#if SHADER_AVAILABLE_RANDOMWRITE #define TYPED_TEXTURE2D(type, textureName) Texture2D textureName #define TYPED_TEXTURE2D_ARRAY(type, textureName) Texture2DArray textureName #define TYPED_TEXTURE3D(type, textureName) Texture3D textureName + +#if SHADER_AVAILABLE_RANDOMWRITE #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName #else -#define TYPED_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture2D) -#define TYPED_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture2DArray) -#define TYPED_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture3D) #define RW_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D) #define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray) #define RW_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D) diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl index 9dacf8d9..cf6760e1 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl @@ -81,17 +81,15 @@ #define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName) #define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName) -#if SHADER_AVAILABLE_RANDOMWRITE #define TYPED_TEXTURE2D(type, textureName) Texture2D textureName #define TYPED_TEXTURE2D_ARRAY(type, textureName) Texture2DArray textureName #define TYPED_TEXTURE3D(type, textureName) Texture3D textureName + +#if SHADER_AVAILABLE_RANDOMWRITE #define RW_TEXTURE2D(type, textureName) RWTexture2D textureName #define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray textureName #define RW_TEXTURE3D(type, textureName) RWTexture3D textureName #else -#define TYPED_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture2D) -#define TYPED_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture2DArray) -#define TYPED_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(TypedTexture3D) #define RW_TEXTURE2D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2D) #define RW_TEXTURE2D_ARRAY(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture2DArray) #define RW_TEXTURE3D(type, textureName) ERROR_ON_UNSUPPORTED_FUNCTION(RWTexture3D) diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl index f42b1699..cfd5cb2f 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl @@ -377,8 +377,8 @@ // Renderpass inputs: General fallback paths #define FRAMEBUFFER_INPUT_FLOAT(idx) TEXTURE2D_FLOAT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize #define FRAMEBUFFER_INPUT_HALF(idx) TEXTURE2D_HALF(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize - #define FRAMEBUFFER_INPUT_INT(idx) TEXTURE2D_INT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize - #define FRAMEBUFFER_INPUT_UINT(idx) TEXTURE2D_UINT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize + #define FRAMEBUFFER_INPUT_INT(idx) TYPED_TEXTURE2D(int4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize + #define FRAMEBUFFER_INPUT_UINT(idx) TYPED_TEXTURE2D(uint4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize #define LOAD_FRAMEBUFFER_INPUT(idx, v2fvertexname) _UnityFBInput##idx.Load(uint3(v2fvertexname.xy, 0)) diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl index f987bacf..7690dd10 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/HDROutput.hlsl @@ -21,9 +21,9 @@ int _HDREncoding; // ACES2065-1: A gamut that covers the full XYZ space, part of the ACES specs. Mostly used for storage since it is harder to work with than ACEScg. // WCG: Wide color gamut. This is defined as a color gamut that is wider than the Rec709 one. // LMS: A color space represented by the response of the three cones of human eye (responsivity peaks Long, Medium, Short) -// OETF (Optical Eelectro Transfer Function): This is a function to goes from optical (linear light) to electro (signal transmitted to the display). -// EOTF (Eelectro Optical Transfer Function): The inverse of the OETF, used by the TV/Monitor. -// EETF (Eelectro-Electro Transfer Function): This is generally just a remapping function, we use the BT2390 EETF to perform range reduction based on the actual display. +// OETF (Optical-Electro Transfer Function): This is a function to goes from optical (linear light) to electro (signal transmitted to the display). +// EOTF (Electro-Optical Transfer Function): The inverse of the OETF, used by the TV/Monitor. +// EETF (Electro-Electro Transfer Function): This is generally just a remapping function, we use the BT2390 EETF to perform range reduction based on the actual display. // PQ (Perceptual Quantizer): the EOTF used for HDR10 TVs. It works in the range [0, 10000] nits. Important to keep in mind that this represents an absolute intensity and not relative as for SDR. Sometimes this can be referenced as ST2084. As OETF we'll use the inverse of the PQ curve. // scRGB: a wide color gamut that uses same color space and white point as sRGB, but with much wider coordinates. Used on windows when 16 bit depth is selected. Most of the color space is imaginary colors. Works differently than with PQ (encoding is linear). // G22 (Gamma 2.2): the EOTF used for exact gamma 2.2 curve. @@ -151,6 +151,17 @@ float3 RotateRec2020ToP3D65(float3 Rec2020Input) return mul(Rec2020ToP3D65Mat, Rec2020Input); } +float3 RotateP3D65ToRec709(float3 P3D65Input) +{ + static const float3x3 P3D65ToRec709Mat = float3x3( + 1.224940, -0.224940, 0.000000, + -0.042057, 1.042057, 0.000000, + -0.019638, -0.078635, 1.098274 + ); + + return mul(P3D65ToRec709Mat, P3D65Input); +} + float3 RotateP3D65ToRec2020(float3 P3D65Input) { static const float3x3 P3D65ToRec2020Mat = float3x3( @@ -195,6 +206,22 @@ float3 RotateRec2020ToOutputSpace(float3 Rec2020Input) } } +float3 RotateOutputSpaceToRec709(float3 ODTInput) +{ + if (_HDRColorspace == HDRCOLORSPACE_REC2020) + { + return RotateRec2020ToRec709(ODTInput); + } + else if (_HDRColorspace == HDRCOLORSPACE_P3D65) + { + return RotateP3D65ToRec709(ODTInput); + } + else // HDRCOLORSPACE_REC709 + { + return ODTInput; + } +} + float3 RotateRec2020ToLMS(float3 Rec2020Input) { diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl index 88eda82a..8c4dfa17 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl @@ -19,6 +19,7 @@ static const float kSHBasisCoef[] = { kSHBasis0, -kSHBasis1, kSHBasis1, -kSHBasi #define kClampedCosine0 (1.0f) #define kClampedCosine1 (2.0f / 3.0f) #define kClampedCosine2 (1.0f / 4.0f) +#define kInvClampedCosine1 (3.0f / 2.0f) static const float kClampedCosineCoefs[] = { kClampedCosine0, kClampedCosine1, kClampedCosine1, kClampedCosine1, kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2 }; diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl index 5200189d..e1fa9fde 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl @@ -60,6 +60,7 @@ #define TEXTURE2D_X_ARGS TEXTURE2D_ARRAY_ARGS #define TEXTURE2D_X_HALF TEXTURE2D_ARRAY_HALF #define TEXTURE2D_X_FLOAT TEXTURE2D_ARRAY_FLOAT + // WW1MOD: reinstated uint texture type macros, because these things are actually used in places #define TEXTURE2D_X_UINT(textureName) Texture2DArray textureName #define TEXTURE2D_X_UINT2(textureName) Texture2DArray textureName #define TEXTURE2D_X_UINT4(textureName) Texture2DArray textureName @@ -89,6 +90,7 @@ #define TEXTURE2D_X_ARGS TEXTURE2D_ARGS #define TEXTURE2D_X_HALF TEXTURE2D_HALF #define TEXTURE2D_X_FLOAT TEXTURE2D_FLOAT + // WW1MOD: reinstated uint texture type macros, because these things are actually used in places #define TEXTURE2D_X_UINT(textureName) Texture2D textureName #define TEXTURE2D_X_UINT2(textureName) Texture2D textureName #define TEXTURE2D_X_UINT4(textureName) Texture2D textureName @@ -201,8 +203,8 @@ // Use regular texture loads as a fallback these can be either 2d or array depending on the TEXTURE2D_X (USE_TEXTURE2D_X_AS_ARRAY) macros #define FRAMEBUFFER_INPUT_X_HALF(idx) TEXTURE2D_X_HALF(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize #define FRAMEBUFFER_INPUT_X_FLOAT(idx) TEXTURE2D_X_FLOAT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize -#define FRAMEBUFFER_INPUT_X_INT(idx) TEXTURE2D_X_INT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize -#define FRAMEBUFFER_INPUT_X_UINT(idx) TEXTURE2D_X_UINT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_INT(idx) TYPED_TEXTURE2D_X(int4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_UINT(idx) TYPED_TEXTURE2D_X(uint4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize #define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fvertexname) LOAD_TEXTURE2D_X(_UnityFBInput##idx,v2fvertexname.xy) #define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) TEXTURE2D_X_MSAA(float4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute b/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute new file mode 100644 index 00000000..4b680853 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute @@ -0,0 +1,20 @@ +#pragma kernel CSMain + +RWStructuredBuffer resultBuffer; +Texture2D _DepthTexture; // Depth Texture Array + +[numthreads(1, 1, 1)] +void CSMain(uint3 id : SV_DispatchThreadID) +{ + // 2D pixel coordinates within the 4x4 texture + int2 pixelCoord = int2(id.xy); + + // Load depth value from the texture array (layer 0, mip level 0) + float depth = _DepthTexture.Load(int3(pixelCoord, 0)); + + // Flatten 2D pixel coordinates (x, y) into a 1D index for resultBuffer + int index = pixelCoord.y * 4 + pixelCoord.x; + + // Write the depth value to the structured buffer + resultBuffer[index] = depth; +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute.meta new file mode 100644 index 00000000..26b5255f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6666e5f03ff07054dbb7a7ac6e6aaee0 +ComputeShaderImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs new file mode 100644 index 00000000..09089924 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs @@ -0,0 +1,51 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityEditor.Rendering.Tests +{ + partial class RenderingDebuggerTests + { + class Volumes + { + static TestCaseData[] s_TestCaseDatasVolumeParameters = + { + new TestCaseData(null).Returns("N/A"), new TestCaseData(new FloatParameter(101.01f)).Returns("101.01"), + new TestCaseData(new BoolParameter(true)).Returns("True"), + new TestCaseData(new BoolParameter(false)).Returns("False"), + new TestCaseData(new IntParameter(1000)).Returns("1000"), + new TestCaseData(new ColorParameter(Color.red)).Returns("RGBA(1.000, 0.000, 0.000, 1.000)"), + new TestCaseData(new IntParameter(1000, overrideState: false)).Returns("1000"), // Extract value should give the proper value + }; + + [Test, TestCaseSource(nameof(s_TestCaseDatasVolumeParameters))] + public string ExtractResult(VolumeParameter parameter) + { + return DebugDisplaySettingsVolume.ExtractResult(parameter); + } + + static TestCaseData[] s_TestCaseDatasCreateParameterWidget = + { + new TestCaseData(null).Returns("N/A"), + new TestCaseData(new FloatParameter(101.01f, overrideState: true)).Returns("101.01"), + new TestCaseData(new BoolParameter(true, overrideState: true)).Returns("True"), + new TestCaseData(new BoolParameter(false, overrideState: true)).Returns("False"), + new TestCaseData(new IntParameter(1000, overrideState: true)).Returns("1000"), + new TestCaseData(new ColorParameter(Color.red, overrideState: true)).Returns("RGBA(1.000, 0.000, 0.000, 1.000)"), + new TestCaseData(new IntParameter(1000, overrideState: false)).Returns("1000"), + }; + + [Test, TestCaseSource(nameof(s_TestCaseDatasCreateParameterWidget))] + public string CreateParameterWidget(VolumeParameter parameter) + { + var widget = DebugDisplaySettingsVolume.WidgetFactory.CreateVolumeParameterWidget(string.Empty, false, parameter); + if (widget is DebugUI.Value value) + return value.getter() as string; + if (widget is DebugUI.ColorField colorField) + return colorField.getter().ToString(); + + return "Not Implemented"; + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs.meta new file mode 100644 index 00000000..205def69 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/VolumePanelTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 27ad958e620b5d34bb958b66d9f58046 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs index e459dcbb..5468c2dc 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs @@ -214,6 +214,8 @@ namespace UnityEngine.Rendering.Tests m_DynamicArray.Add(2); Assert.AreEqual(-1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 4)); + + Assert.AreEqual(-1, m_DynamicArray.FindIndex((x) => x == 4)); } [Test] @@ -225,6 +227,23 @@ namespace UnityEngine.Rendering.Tests m_DynamicArray.Add(2); Assert.AreEqual(1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 2)); + Assert.AreEqual(3, m_DynamicArray.FindIndex(2, 2, (x) => x == 2)); + + Assert.AreEqual(1, m_DynamicArray.FindIndex((x) => x == 2)); + } + + [Test] + public void TestFindIndexDoesNotFindOutsideCount() + { + m_DynamicArray.Add(1); + m_DynamicArray.Add(2); + m_DynamicArray.Add(3); + m_DynamicArray.Add(4); + + Assert.AreEqual(-1, m_DynamicArray.FindIndex(1, 2, (x) => x == 1)); + Assert.AreEqual(1, m_DynamicArray.FindIndex(1, 2, (x) => x == 2)); + Assert.AreEqual(2, m_DynamicArray.FindIndex(1, 2, (x) => x == 3)); + Assert.AreEqual(-1, m_DynamicArray.FindIndex(1, 2, (x) => x == 4)); } [Test] diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs index ba153916..dda2d068 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs @@ -38,6 +38,7 @@ namespace UnityEngine.Rendering.Tests private RenderPipelineAsset m_OldPipelineAsset; private GPUResidentDrawerResources m_Resources; private RenderPassGlobalSettings m_GlobalSettings; + private bool m_oldEnableLodCrossFade; class BoxedCounter { @@ -85,6 +86,8 @@ namespace UnityEngine.Rendering.Tests m_OldPipelineAsset = GraphicsSettings.defaultRenderPipeline; GraphicsSettings.defaultRenderPipeline = m_RenderPipe; m_Resources = GraphicsSettings.GetRenderPipelineSettings(); + m_oldEnableLodCrossFade = QualitySettings.enableLODCrossFade; + QualitySettings.enableLODCrossFade = true; } [TearDown] @@ -93,6 +96,7 @@ namespace UnityEngine.Rendering.Tests m_RenderPipe = null; m_MeshTestData.Dispose(); GraphicsSettings.defaultRenderPipeline = m_OldPipelineAsset; + QualitySettings.enableLODCrossFade = m_oldEnableLodCrossFade; } [Test, ConditionalIgnore("IgnoreGfxAPI", "Graphics API Not Supported.")] @@ -647,7 +651,7 @@ namespace UnityEngine.Rendering.Tests { BatchDrawCommand cmd = drawCommands.drawCommands[range.drawCommandsBegin + i]; Assert.AreEqual(expectedMeshIDs[i], cmd.meshID.value, "Incorrect mesh rendered"); - Assert.AreEqual(cmd.flags & BatchDrawCommandFlags.LODCrossFade, expectedFlags[i], "Incorrect flag for the current draw command"); + Assert.AreEqual(expectedFlags[i], cmd.flags & BatchDrawCommandFlags.LODCrossFade, "Incorrect flag for the current draw command"); } } }; @@ -759,6 +763,9 @@ namespace UnityEngine.Rendering.Tests rbcDesc.supportDitheringCrossFade = true; rbcDesc.smallMeshScreenPercentage = 10.0f; + var lastLodBias = QualitySettings.lodBias; + QualitySettings.lodBias = 1.0f; + var gpuDrivenProcessor = new GPUDrivenProcessor(); using (var brgContext = new RenderersBatchersContext(rbcDesc, gpuDrivenProcessor, m_Resources)) @@ -785,7 +792,7 @@ namespace UnityEngine.Rendering.Tests { BatchDrawCommand cmd = drawCommands.drawCommands[range.drawCommandsBegin + i]; Assert.AreEqual(expectedMeshIDs[i], cmd.meshID.value, "Incorrect mesh rendered"); - Assert.AreEqual(cmd.flags & BatchDrawCommandFlags.LODCrossFade, expectedFlags[i], "Incorrect flag for the current draw command"); + Assert.AreEqual(expectedFlags[i], cmd.flags & BatchDrawCommandFlags.LODCrossFade, "Incorrect flag for the current draw command"); } } }; @@ -816,7 +823,7 @@ namespace UnityEngine.Rendering.Tests expectedFlags.Clear(); expectedFlags.Add(BatchDrawCommandFlags.LODCrossFadeValuePacked); expectedFlags.Add(BatchDrawCommandFlags.LODCrossFade); - expectedDrawCommandCount = 1; + expectedDrawCommandCount = 2; cameraObject.transform.position = new Vector3(0.0f, 0.0f, -8.5f); SubmitCameraRenderRequest(mainCamera); @@ -839,6 +846,8 @@ namespace UnityEngine.Rendering.Tests } } + QualitySettings.lodBias = lastLodBias; + gpuDrivenProcessor.Dispose(); objIDs.Dispose(); diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/RemoveRange.Extensions.Tests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/RemoveRange.Extensions.Tests.cs index f82c8803..824763fa 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/RemoveRange.Extensions.Tests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/RemoveRange.Extensions.Tests.cs @@ -23,9 +23,8 @@ namespace UnityEditor.Rendering.Tests where TList : IList { using (ListPool.Get(out var copy)) - { - foreach (int integer in list) - copy.Add(integer); + { + copy.AddRange(list); if (list.TryRemoveElementsInRange(startIndex, count, out var exception)) { diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraph.ComputeGraphHash.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraph.ComputeGraphHash.cs index 2173abae..adc3d8d6 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraph.ComputeGraphHash.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraph.ComputeGraphHash.cs @@ -8,32 +8,32 @@ namespace UnityEngine.Rendering.Tests { class RegularMethodInRegularClass { - public void RenderFunc(RenderGraphTestPassData data, RenderGraphContext context) + public void RenderFunc(RenderGraphTestPassData data, RasterGraphContext context) { } } static class StaticMethodInsideStaticClass { - public static void RenderFunc(RenderGraphTestPassData data, RenderGraphContext context) + public static void RenderFunc(RenderGraphTestPassData data, RasterGraphContext context) { } } class StaticMethodInsideRegularClass { - public static void RenderFunc(RenderGraphTestPassData data, RenderGraphContext context) + public static void RenderFunc(RenderGraphTestPassData data, RasterGraphContext context) { } - public static void RenderFunc2(RenderGraphTestPassData data, RenderGraphContext context) + public static void RenderFunc2(RenderGraphTestPassData data, UnsafeGraphContext context) { } } class StaticMethodInsideRegularClass2 { - public static void RenderFunc(RenderGraphTestPassData data, RenderGraphContext context) + public static void RenderFunc(RenderGraphTestPassData data, UnsafeGraphContext context) { } } @@ -49,47 +49,47 @@ namespace UnityEngine.Rendering.Tests { //Method of the class instance TextureHandle texture0 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) { - builder.UseColorBuffer(texture0, 0); + builder.SetRenderAttachment(texture0, 0, AccessFlags.Write); var firstInstance = new RegularMethodInRegularClass(); builder.SetRenderFunc(firstInstance.RenderFunc); } //Static method of the static class TextureHandle texture1 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass1", out var passData)) { - builder.UseColorBuffer(texture1, 0); + builder.SetRenderAttachment(texture1, 0, AccessFlags.Write); builder.SetRenderFunc(StaticMethodInsideStaticClass.RenderFunc); } //Lambdas with captured variable TextureHandle texture2 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass2", out var passData)) { - builder.UseColorBuffer(texture2, 0); + builder.SetRenderAttachment(texture2, 0, AccessFlags.Write); builder.SetRenderFunc((data, context) => { Debug.Log(texture2.GetHashCode()); }); } //Local method with captured variable TextureHandle texture3 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - using (var builder = m_RenderGraph.AddRenderPass("TestPass3", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass3", out var passData)) { - builder.UseColorBuffer(texture3, 0); + builder.SetRenderAttachment(texture3, 0, AccessFlags.Write); builder.SetRenderFunc(LocalMethod); } - void LocalMethod(RenderGraphTestPassData data, RenderGraphContext renderGraphContext) + void LocalMethod(RenderGraphTestPassData data, RasterGraphContext renderGraphContext) { Debug.Log(texture3.GetHashCode()); } //Static method of the regular class TextureHandle texture4 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - using (var builder = m_RenderGraph.AddRenderPass("TestPass4", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass4", out var passData)) { - builder.UseColorBuffer(texture4, 0); + builder.SetRenderAttachment(texture4, 0, AccessFlags.Write); builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc); } @@ -123,7 +123,7 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph, RegularMethodInRegularClass instance) { - using var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData); + using var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData); builder.SetRenderFunc(instance.RenderFunc); } } @@ -131,13 +131,13 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHash_WhenDifferentStaticMethodsWithTheSameNameUsed_HashcodeIsDifferent() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc); var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass2.RenderFunc); var hash1 = m_RenderGraph.ComputeGraphHash(); @@ -149,26 +149,26 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHash_WhenManyDifferentPassesUsed_HashcodeIsDifferent() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { } - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { } var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { } @@ -218,8 +218,8 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph, TextureDesc desc) { var texture0 = renderGraph.CreateTexture(desc); - using var builder = renderGraph.AddRenderPass("TestPass0", out var passData); - builder.UseColorBuffer(texture0, 0); + using var builder = renderGraph.AddRasterRenderPass("TestPass0", out var passData); + builder.SetRenderAttachment(texture0, 0, AccessFlags.Write); } } @@ -228,13 +228,13 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHash_WhenUsedLambdasDiffer_HashcodeIsDifferent() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc((_, _) => { }); var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc((_, _) => { }); var hash1 = m_RenderGraph.ComputeGraphHash(); @@ -246,13 +246,13 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHash_WhenUsedStaticMethodsDiffer_HashcodeIsDifferent() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc); var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc2); var hash1 = m_RenderGraph.ComputeGraphHash(); @@ -276,15 +276,15 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph) { - using (var builder = renderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass0", out var passData)) { } - using (var builder = renderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass1", out var passData)) { } - using (var builder = renderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass2", out var passData)) { } } @@ -293,12 +293,12 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHashForTheSameSetup_WhenStaticsInStaticClassUsed_HashcodeIsSame() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideStaticClass.RenderFunc); var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideStaticClass.RenderFunc); var hash1 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); @@ -309,12 +309,12 @@ namespace UnityEngine.Rendering.Tests [Test] public void ComputeGraphHashForTheSameSetup_WhenStaticsInRegularClassUsed_HashcodeIsSame() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc); var hash0 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) builder.SetRenderFunc(StaticMethodInsideRegularClass.RenderFunc); var hash1 = m_RenderGraph.ComputeGraphHash(); ClearCompiledGraphAndHash(); @@ -339,13 +339,13 @@ namespace UnityEngine.Rendering.Tests static void RecordRenderGraph(RenderGraph renderGraph) { - using (var builder = renderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc((p, c) => { }); - using (var builder = renderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass1", out var passData)) builder.SetRenderFunc((p, c) => { }); - using (var builder = renderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass2", out var passData)) builder.SetRenderFunc((p, c) => { }); } } @@ -369,7 +369,7 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph, TextureHandle handle) { - using var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData); + using var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData); builder.SetRenderFunc((data, context) => { if (!handle.IsValid()) @@ -395,17 +395,17 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph) { - using (var builder = renderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc(LocalRenderFunc); - using (var builder = renderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass1", out var passData)) builder.SetRenderFunc(LocalRenderFunc); - using (var builder = renderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass2", out var passData)) builder.SetRenderFunc(LocalRenderFunc); } - void LocalRenderFunc(RenderGraphTestPassData data, RenderGraphContext renderGraphContext) + void LocalRenderFunc(RenderGraphTestPassData data, UnsafeGraphContext renderGraphContext) { } } @@ -428,18 +428,18 @@ namespace UnityEngine.Rendering.Tests void RecordRenderGraph(RenderGraph renderGraph) { var outerScopeVariable = "1"; - using (var builder = renderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass0", out var passData)) builder.SetRenderFunc(LocalRenderFunc); outerScopeVariable = "2"; - using (var builder = renderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass1", out var passData)) builder.SetRenderFunc(LocalRenderFunc); outerScopeVariable = "3"; - using (var builder = renderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = renderGraph.AddUnsafePass("TestPass2", out var passData)) builder.SetRenderFunc(LocalRenderFunc); - void LocalRenderFunc(RenderGraphTestPassData data, RenderGraphContext renderGraphContext) + void LocalRenderFunc(RenderGraphTestPassData data, UnsafeGraphContext renderGraphContext) => Debug.Log(outerScopeVariable); } } diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs index c5d5fc6a..7e9e0af6 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs @@ -5,6 +5,7 @@ using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.TestTools; using Unity.Collections; +using UnityEngine.Rendering.RendererUtils; #if UNITY_EDITOR using UnityEditor; @@ -31,6 +32,8 @@ namespace UnityEngine.Rendering.Tests partial class RenderGraphTests { + const string k_InvalidOperationMessage = "InvalidOperationException: "; + // For RG Record/Hash/Compile testing, use m_RenderGraph RenderGraph m_RenderGraph; @@ -41,6 +44,8 @@ namespace UnityEngine.Rendering.Tests RenderGraphTestPipelineAsset m_RenderGraphTestPipeline; RenderGraphTestGlobalSettings m_RenderGraphTestGlobalSettings; + Dictionary> m_GraphStateActions = new Dictionary>(); + // We need a camera to execute the render graph and a game object to attach a camera GameObject m_GameObject; Camera m_Camera; @@ -93,9 +98,23 @@ namespace UnityEngine.Rendering.Tests invalidContextForTesting = false }; - m_RenderGraph.BeginRecording(rgParams); + try + { + // Necessary to reinitialize the state, since we have many tests which do not use this system but directly adding + // passes to the graph (to test the compilation) and destroying them without executing them with camera.Render() + // (e.g GraphicsPassWriteWaitOnAsyncPipe). So the state becomes RecordGraph because of the Builder.Destroy logic. + m_RenderGraph.RenderGraphState = RenderGraphState.Idle; + + m_RenderGraph.BeginRecording(rgParams); - asset.recordRenderGraphBody?.Invoke(renderContext, camera, cmd); + asset.recordRenderGraphBody?.Invoke(renderContext, camera, cmd); + } + catch (Exception e) + { + if (m_RenderGraph.ResetGraphAndLogException(e)) + throw; + return; + } m_RenderGraph.EndRecordingAndExecute(); @@ -134,9 +153,11 @@ namespace UnityEngine.Rendering.Tests // Getting the RG from the custom asset pipeline m_RenderGraph = m_RenderGraphTestPipeline.renderGraph; - m_RenderGraph.nativeRenderPassesEnabled = true; + // Necessary to disable it for the Unit Tests, as the caller is not the same. + RenderGraph.RenderGraphExceptionMessages.enableCaller = false; + // We need a real ScriptableRenderContext and a camera to execute the Render Graph m_GameObject = new GameObject("testGameObject") { @@ -174,7 +195,7 @@ namespace UnityEngine.Rendering.Tests { // Cleaning all Render Graph resources and data structures // Nothing remains, Render Graph in next test will start from scratch - m_RenderGraph.Cleanup(); + m_RenderGraph.ForceCleanup(); } class RenderGraphTestPassData @@ -187,10 +208,10 @@ namespace UnityEngine.Rendering.Tests [Test] public void WriteToBackBufferNotCulled() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -204,10 +225,14 @@ namespace UnityEngine.Rendering.Tests [Test] public void NoWriteToBackBufferCulled() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture( + m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) + { + colorFormat = GraphicsFormat.R8G8B8A8_UNorm + }), AccessFlags.WriteAll); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -221,10 +246,10 @@ namespace UnityEngine.Rendering.Tests [Test] public void WriteToImportedTextureNotCulled() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - builder.WriteTexture(m_RenderGraph.ImportTexture(null)); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(m_RenderGraph.ImportTexture(null), AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -237,10 +262,10 @@ namespace UnityEngine.Rendering.Tests [Test] public void WriteToImportedComputeBufferNotCulled() { - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - builder.WriteBuffer(m_RenderGraph.ImportBuffer(null)); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseBuffer(m_RenderGraph.ImportBuffer(null), AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -254,36 +279,36 @@ namespace UnityEngine.Rendering.Tests public void PassWriteResourcePartialNotReadAfterNotCulled() { // If a pass writes to a resource that is not unused globally by the graph but not read ever AFTER the pass then the pass should be culled unless it writes to another used resource. - TextureHandle texture0; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + TextureHandle texture0 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - TextureHandle texture1; - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + TextureHandle texture1 = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - builder.ReadTexture(texture0); - texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(texture1, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // This pass writes to texture0 which is used so will not be culled out. // Since texture0 is never read after this pass, we should decrement refCount for this pass and potentially cull it. // However, it also writes to texture1 which is used in the last pass so we mustn't cull it. - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { - builder.WriteTexture(texture0); - builder.WriteTexture(texture1); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.UseTexture(texture1, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass3", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass3", out var passData)) { - builder.ReadTexture(texture1); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture1, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -300,10 +325,10 @@ namespace UnityEngine.Rendering.Tests public void PassDisallowCullingNotCulled() { // This pass does nothing so should be culled but we explicitly disallow it. - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { builder.AllowPassCulling(false); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -317,19 +342,25 @@ namespace UnityEngine.Rendering.Tests [Test] public void PartialUnusedProductNotCulled() { - TextureHandle texture; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) - { - texture = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + TextureHandle texture = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) + { + builder.UseTexture(texture, AccessFlags.Write); + builder.UseTexture( + m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) + { + colorFormat = GraphicsFormat.R8G8B8A8_UNorm + }), AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - builder.ReadTexture(texture); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -344,27 +375,29 @@ namespace UnityEngine.Rendering.Tests [Test] public void SimpleCreateReleaseTexture() { - TextureHandle texture; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + TextureHandle texture = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - texture = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Add dummy passes for (int i = 0; i < 2; ++i) { - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } } - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { - builder.ReadTexture(texture); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -381,17 +414,17 @@ namespace UnityEngine.Rendering.Tests Assert.Catch(() => { TextureHandle texture; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { texture = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - builder.ReadTexture(texture); // This is illegal (transient resource was created in previous pass) - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture, AccessFlags.Read); // This is illegal (transient resource was created in previous pass) + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -402,11 +435,11 @@ namespace UnityEngine.Rendering.Tests public void TransientCreateReleaseInSamePass() { TextureHandle texture; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { texture = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -422,61 +455,68 @@ namespace UnityEngine.Rendering.Tests [Test] public void AsyncPassReleaseTextureOnGraphicsPipe() { - TextureHandle texture0; - TextureHandle texture1; - TextureHandle texture2; - TextureHandle texture3; + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + TextureHandle texture1 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + TextureHandle texture2; // transient texture + TextureHandle texture3 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + // First pass creates and writes two textures. - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass0", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); + builder.UseTexture(texture0, AccessFlags.Write); + builder.UseTexture(texture1, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Second pass creates a transient texture => Create/Release should happen in this pass but we want to delay the release until the first graphics pipe pass that sync with async queue. - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass1", out var passData)) { texture2 = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - builder.WriteTexture(texture0); + builder.UseTexture(texture0, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // This pass is the last to read texture0 => Release should happen in this pass but we want to delay the release until the first graphics pipe pass that sync with async queue. - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass2", out var passData)) { - texture0 = builder.ReadTexture(texture0); - builder.WriteTexture(texture1); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(texture1, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Just here to add "padding" to the number of passes to ensure resources are not released right at the first sync pass. - using (var builder = m_RenderGraph.AddRenderPass("TestPass3", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass3", out var passData)) { - texture3 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); + builder.UseTexture(texture3, AccessFlags.Write); builder.EnableAsyncCompute(false); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Pass prior to synchronization should be where textures are released. - using (var builder = m_RenderGraph.AddRenderPass("TestPass4", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass4", out var passData)) { - builder.WriteTexture(texture3); + builder.UseTexture(texture3, AccessFlags.Write); builder.EnableAsyncCompute(false); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Graphics pass that reads texture1. This will request a sync with compute pipe. The previous pass should be the one releasing async textures. - using (var builder = m_RenderGraph.AddRenderPass("TestPass5", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass5", out var passData)) { - builder.ReadTexture(texture1); - builder.ReadTexture(texture3); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled + builder.UseTexture(texture1, AccessFlags.Read); + builder.UseTexture(texture3, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled builder.EnableAsyncCompute(false); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -490,27 +530,29 @@ namespace UnityEngine.Rendering.Tests [Test] public void TransientResourceNotCulled() { - TextureHandle texture0; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); - builder.WriteTexture(texture0); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Graphics pass that reads texture1. This will request a sync with compute pipe. The previous pass should be the one releasing async textures. - using (var builder = m_RenderGraph.AddRenderPass("TestPass5", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass5", out var passData)) { - builder.ReadTexture(texture0); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled builder.EnableAsyncCompute(false); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -523,25 +565,27 @@ namespace UnityEngine.Rendering.Tests [Test] public void AsyncPassWriteWaitOnGraphicsPipe() { - TextureHandle texture0; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass1", out var passData)) { - texture0 = builder.WriteTexture(texture0); + builder.UseTexture(texture0, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { - builder.ReadTexture(texture0); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -555,27 +599,32 @@ namespace UnityEngine.Rendering.Tests [Test] public void AsyncPassReadWaitOnGraphicsPipe() { - TextureHandle texture0; - TextureHandle texture1; - using (var builder = m_RenderGraph.AddRenderPass("TestPass0", out var passData)) + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + TextureHandle texture1 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + + using (var builder = m_RenderGraph.AddUnsafePass("TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass1", out var passData)) { - builder.ReadTexture(texture0); - texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(texture1, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { - builder.ReadTexture(texture1); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture1, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -589,27 +638,30 @@ namespace UnityEngine.Rendering.Tests [Test] public void GraphicsPassWriteWaitOnAsyncPipe() { - TextureHandle texture0; - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass0", out var passData)) + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); + builder.UseTexture(texture0, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // This pass should sync with the "Async_TestPass0" - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - texture0 = builder.WriteTexture(texture0); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } // Read result and output to backbuffer to avoid culling passes. - using (var builder = m_RenderGraph.AddRenderPass("TestPass2", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass2", out var passData)) { - builder.ReadTexture(texture0); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -622,19 +674,22 @@ namespace UnityEngine.Rendering.Tests [Test] public void GraphicsPassReadWaitOnAsyncPipe() { - TextureHandle texture0; - using (var builder = m_RenderGraph.AddRenderPass("Async_TestPass0", out var passData)) + TextureHandle texture0 = + m_RenderGraph.CreateTexture( + new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + + using (var builder = m_RenderGraph.AddUnsafePass("Async_TestPass0", out var passData)) { - texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm })); + builder.UseTexture(texture0, AccessFlags.Write); builder.EnableAsyncCompute(true); - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } - using (var builder = m_RenderGraph.AddRenderPass("TestPass1", out var passData)) + using (var builder = m_RenderGraph.AddUnsafePass("TestPass1", out var passData)) { - builder.ReadTexture(texture0); - builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled - builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { }); + builder.UseTexture(texture0, AccessFlags.Read); + builder.UseTexture(m_RenderGraph.ImportBackbuffer(0), AccessFlags.Write); // Needed for the passes to not be culled + builder.SetRenderFunc((RenderGraphTestPassData data, UnsafeGraphContext context) => { }); } m_RenderGraph.CompileRenderGraph(m_RenderGraph.ComputeGraphHash()); @@ -791,7 +846,7 @@ namespace UnityEngine.Rendering.Tests var importedDesc = importedTexture.GetDescriptor(m_RenderGraph); Assert.AreEqual(textureDesc.format, importedDesc.format); - } + } textureDesc.colorFormat = formatR32; Assert.AreEqual(textureDesc.depthBufferBits, DepthBits.None); @@ -802,7 +857,7 @@ namespace UnityEngine.Rendering.Tests var importedDesc = importedTexture.GetDescriptor(m_RenderGraph); Assert.AreEqual(textureDesc.format, importedDesc.format); - } + } } [Test] @@ -899,7 +954,7 @@ namespace UnityEngine.Rendering.Tests { builder.AllowPassCulling(false); - // no render func + // no render func } }; LogAssert.Expect(LogType.Error, "Render Graph Execution error"); @@ -907,6 +962,138 @@ namespace UnityEngine.Rendering.Tests m_Camera.Render(); } + [Test] + public void UsingAddRenderPassWithNRPThrows() + { + // m_RenderGraph.nativeRenderPassesEnabled is set to true in the setup + // record and execute render graph calls + m_RenderGraphTestPipeline.recordRenderGraphBody = (context, camera, cmd) => + { + using var builder = m_RenderGraph.AddRenderPass("HDRP Render Pass", out var passData); + }; + + LogAssert.Expect(LogType.Error, "Render Graph Execution error"); + LogAssert.Expect(LogType.Exception, + "InvalidOperationException: `AddRenderPass` is not compatible with the Native Render Pass Compiler. It is meant to be used with the HDRP Compiler. " + + "The APIs that are compatible with the Native Render Pass Compiler are AddUnsafePass, AddComputePass and AddRasterRenderPass."); + + m_Camera.Render(); + } + + class TestBufferTextureComputeData + { + public BufferHandle bufferHandle; + public TextureHandle depthTexture; + public ComputeShader computeShader; + } + + [Test, ConditionalIgnore("IgnoreGraphicsAPI", "Compute Shaders are not supported for this Graphics API.")] + public void RenderGraphClearDepthTextureWithDepthReadOnlyFlag() + { + const int kWidth = 4; + const int kHeight = 4; + const string kPathComputeShader = "Packages/com.unity.render-pipelines.core/Tests/Editor/CopyDepthToBuffer.compute"; + + var computeShader = AssetDatabase.LoadAssetAtPath(kPathComputeShader); + // Check if the compute shader was loaded successfully + if (computeShader == null) + { + Debug.LogError("Compute Shader not found!"); + return; + } + + // Define the size of the buffer (number of elements) + int bufferSize = kWidth*kHeight; // We are only interested in the first four values + + // Allocate the buffer with the given size and format + var buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, bufferSize, sizeof(float)); + + // Initialize the buffer with zeros + float[] initialData = new float[bufferSize]; + + + // Ensure the data is set to 0.0f + for (int i = 0; i < bufferSize; i++) + { + initialData[i] = 1.0f; + } + + buffer.SetData(initialData); + + m_RenderGraphTestPipeline.recordRenderGraphBody = (context, camera, cmd) => + { + TextureHandle texture0 = m_RenderGraph.CreateTexture(new TextureDesc(kWidth, kHeight) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + TextureHandle texture1 = m_RenderGraph.CreateTexture(new TextureDesc(kWidth, kHeight) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }); + + TextureHandle depthTexture = m_RenderGraph.CreateTexture(new TextureDesc(kWidth, kHeight) { colorFormat = GraphicsFormat.D16_UNorm }); + // no depth + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass0", out var passData)) + { + + builder.SetRenderAttachment(texture0, 0, AccessFlags.Write); + builder.UseTexture(texture1, AccessFlags.Read); + builder.AllowPassCulling(false); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // with depth + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachment(texture0, 0, AccessFlags.Write); + builder.SetRenderAttachmentDepth(depthTexture, AccessFlags.Write); + builder.AllowPassCulling(false); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // Compute pass + using (var builder = m_RenderGraph.AddComputePass("TestPass Compute", out var passData)) + { + builder.AllowPassCulling(false); + + // Import resources into the Render Graph + passData.bufferHandle = m_RenderGraph.ImportBuffer(buffer); // Import external ComputeBuffer + passData.depthTexture = depthTexture; // Import RTHandle texture + + builder.UseBuffer(passData.bufferHandle, AccessFlags.Write); // Ensure correct usage of the buffer + builder.UseTexture(passData.depthTexture, AccessFlags.ReadWrite); + + // Assign the compute shader + passData.computeShader = computeShader; + + builder.SetRenderFunc((TestBufferTextureComputeData data, ComputeGraphContext ctx) => + { + int kernel = data.computeShader.FindKernel("CSMain"); + + ctx.cmd.SetComputeBufferParam(data.computeShader, kernel, "resultBuffer", data.bufferHandle); + ctx.cmd.SetComputeTextureParam(data.computeShader, kernel, "_DepthTexture", data.depthTexture); + ctx.cmd.DispatchCompute(data.computeShader, kernel, kWidth, kHeight, 1); + }); + } + + var result = m_RenderGraph.CompileNativeRenderGraph(m_RenderGraph.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + Assert.AreEqual(1, passes.Count); // 1 native Pass + compute + Assert.AreEqual(2, passes[0].numNativeSubPasses); + Assert.True(result.contextData.nativeSubPassData[0].flags.HasFlag(SubPassFlags.ReadOnlyDepth)); + }; + m_Camera.Render(); + + // TODO: With current structure of the Tests, nativePassCompiler is not accessible out of recordRenderGraphBody. + // Add checks for the passes.count and checks if first subpass has readOnlyDepth flag in future update + + // Read back the data from the buffer + float[] result2 = new float[bufferSize]; + buffer.GetData(result2); + + buffer.Release(); + + // Ensure the data has been updated + for (int i = 0; i < bufferSize; i++) + { + Assert.IsTrue(result2[i] == 0.0f); + } + } + /* // Disabled for now as version management is not exposed to user code [Test] @@ -970,11 +1157,66 @@ namespace UnityEngine.Rendering.Tests public NativeArray pixels; } - private bool m_AsyncReadbackDone = false; + [Test] + public void ImportedTexturesAreClearedOnFirstUse() + { + bool asyncReadbackDone = false; + const int kWidth = 4; + const int kHeight = 4; + const GraphicsFormat format = GraphicsFormat.R8G8B8A8_SRGB; + + NativeArray pixels = default; + + m_RenderGraphTestPipeline.recordRenderGraphBody = (context, camera, cmd) => + { + var redTexture = CreateRedTexture(kWidth, kHeight); + ImportResourceParams importParams = new ImportResourceParams() + { + clearColor = Color.blue, clearOnFirstUse = true + }; + var importedTexture = m_RenderGraph.ImportTexture(redTexture, importParams); + + pixels = new NativeArray(kWidth * kHeight * 4, Allocator.Persistent, + NativeArrayOptions.UninitializedMemory); + + using (var builder = + m_RenderGraph.AddUnsafePass("ImportedTextureTest", out var passData)) + { + builder.AllowPassCulling(false); + builder.UseTexture(importedTexture, AccessFlags.ReadWrite); + + passData.texture = importedTexture; + passData.pixels = pixels; + + builder.SetRenderFunc((RenderGraphAsyncRequestTestData data, UnsafeGraphContext context) => + { + context.cmd.RequestAsyncReadbackIntoNativeArray(ref data.pixels, data.texture, 0, format, + request => RenderGraphTest_AsyncReadbackCallback(request, ref asyncReadbackDone)); + }); + } + }; + + m_Camera.Render(); + + AsyncGPUReadback.WaitAllRequests(); + Assert.True(asyncReadbackDone); + + // Texture should be clear color instead of original red color + for (int i = 0; i < kWidth * kHeight; i += 4) + { + Assert.True(pixels[i] / 255.0f == Color.blue.r); + Assert.True(pixels[i + 1] / 255.0f == Color.blue.g); + Assert.True(pixels[i + 2] / 255.0f == Color.blue.b); + Assert.True(pixels[i + 3] / 255.0f == Color.blue.a); + } + + pixels.Dispose(); + } [Test] public void RequestAsyncReadbackIntoNativeArrayWorks() { + bool asyncReadbackDone = false; const int kWidth = 4; const int kHeight = 4; const GraphicsFormat format = GraphicsFormat.R8G8B8A8_SRGB; @@ -1006,7 +1248,8 @@ namespace UnityEngine.Rendering.Tests builder.SetRenderFunc((RenderGraphAsyncRequestTestData data, UnsafeGraphContext context) => { - context.cmd.RequestAsyncReadbackIntoNativeArray(ref data.pixels, data.texture, 0, format, RenderGraphTest_AsyncReadbackCallback); + context.cmd.RequestAsyncReadbackIntoNativeArray(ref data.pixels, data.texture, 0, format, + request => RenderGraphTest_AsyncReadbackCallback(request, ref asyncReadbackDone)); }); } }; @@ -1015,7 +1258,7 @@ namespace UnityEngine.Rendering.Tests AsyncGPUReadback.WaitAllRequests(); - Assert.True(m_AsyncReadbackDone); + Assert.True(asyncReadbackDone); for (int i = 0; i < kWidth * kHeight; i += 4) { @@ -1028,16 +1271,16 @@ namespace UnityEngine.Rendering.Tests pixels.Dispose(); } - void RenderGraphTest_AsyncReadbackCallback(AsyncGPUReadbackRequest request) + void RenderGraphTest_AsyncReadbackCallback(AsyncGPUReadbackRequest request, ref bool asyncReadbackDone) { if (request.hasError) { // We shouldn't have any error, asserting. - Assert.True(m_AsyncReadbackDone); + Assert.True(asyncReadbackDone); } else if (request.done) { - m_AsyncReadbackDone = true; + asyncReadbackDone = true; } } @@ -1234,6 +1477,198 @@ namespace UnityEngine.Rendering.Tests }); } }; + } + + [Test] + public void RenderGraphThrowsException_ErrorsWhenRecordingPass() + { + PopulateRecordingPassAPIActions(); + + ExecuteRenderGraphAPIActions(RenderGraphState.RecordingPass); + } + + [Test] + public void RenderGraphThrowsException_ErrorsWhenRecordingGraph() + { + PopulateRecordingGraphAPIActions(); + + ExecuteRenderGraphAPIActions(RenderGraphState.RecordingGraph); + } + + [Test] + public void RenderGraphThrowsException_ErrorsWhenExecutingGraph() + { + PopulateExecutingAPIActions(); + + ExecuteRenderGraphAPIActions(RenderGraphState.Executing); + } + + [Test] + public void RenderGraphThrowsException_ErrorsWhenRecordingPassAndExecutingGraph() + { + PopulateRecordingPassAndExecutingGraphAPIActions(); + + ExecuteRenderGraphAPIActions(RenderGraphState.RecordingPass | RenderGraphState.Executing); + } + + [Test] + public void RenderGraphThrowsException_ErrorsWhenRecordingPassAndGraphAndExecutingGraph() + { + PopulateActiveGraphAPIActions(); + + ExecuteRenderGraphAPIActions(RenderGraphState.Active); + } + + // It's forbidden to use these APIs in RecordingPass mode. + void PopulateRecordingPassAPIActions() + { + var errorAPIPassName = "TestPassMustThrowException"; + var recordingPassActions = new List + { + () => m_RenderGraph.AddRasterRenderPass(errorAPIPassName, out var passData2), + () => m_RenderGraph.AddUnsafePass(errorAPIPassName, out var passData2), + () => m_RenderGraph.AddComputePass(errorAPIPassName, out var passData2), + }; + + m_GraphStateActions.Add(RenderGraphState.RecordingPass, recordingPassActions); + } + + // It's forbidden to use these APIs in RecordingGraph mode. + void PopulateRecordingGraphAPIActions() + { + var recordingGraphActions = new List(); + + // Empty for the moment + m_GraphStateActions.Add(RenderGraphState.RecordingGraph, recordingGraphActions); + } + + // It's forbidden to use these APIs in Executing mode. + void PopulateExecutingAPIActions() + { + var textureHandle = new TextureHandle(); + var flagActions = RenderGraphState.Executing; + var executingActions = new List + { + // Texture APIs + () => m_RenderGraph.CreateTexture(textureHandle), + () => m_RenderGraph.CreateTextureIfInvalid(new TextureDesc(), ref textureHandle), + () => m_RenderGraph.CreateTexture(new TextureDesc()), + () => m_RenderGraph.ImportTexture(null), + () => m_RenderGraph.ImportTexture(null, new ImportResourceParams()), + () => m_RenderGraph.ImportTexture(null, new RenderTargetInfo(), new ImportResourceParams()), + () => m_RenderGraph.ImportTexture(null, isBuiltin: false), + + // Buffer APIs + () => m_RenderGraph.CreateBuffer(new BufferDesc()), + () => m_RenderGraph.CreateBuffer(new BufferHandle()), + () => m_RenderGraph.ImportBuffer(null), + () => m_RenderGraph.ImportBackbuffer(new RenderTargetIdentifier(), new RenderTargetInfo()), + () => m_RenderGraph.ImportBackbuffer(new RenderTargetIdentifier()), + + // RendererList APIs + () => m_RenderGraph.CreateRendererList(new RendererListDesc()), + () => m_RenderGraph.CreateRendererList(new RendererListParams()), + () => m_RenderGraph.CreateGizmoRendererList(m_Camera, GizmoSubset.PreImageEffects), + () => m_RenderGraph.CreateUIOverlayRendererList(m_Camera), + () => m_RenderGraph.CreateUIOverlayRendererList(m_Camera, UISubset.All), + () => m_RenderGraph.CreateWireOverlayRendererList(m_Camera), + () => m_RenderGraph.CreateSkyboxRendererList(m_Camera), + () => m_RenderGraph.CreateSkyboxRendererList(m_Camera, Matrix4x4.identity, Matrix4x4.identity), + () => m_RenderGraph.CreateSkyboxRendererList(m_Camera, Matrix4x4.identity, Matrix4x4.identity, Matrix4x4.identity, Matrix4x4.identity), + + // Other APIs + () => m_RenderGraph.ImportRayTracingAccelerationStructure(null) + }; + + m_GraphStateActions.Add(flagActions, executingActions); + } + + // It's forbidden to use these APIs in RecordingPass and Executing mode. + void PopulateRecordingPassAndExecutingGraphAPIActions() + { + var flagActions = RenderGraphState.RecordingPass | RenderGraphState.Executing; + var recordingPassAndExecutingActions = new List + { + () => m_RenderGraph.EndRecordingAndExecute() + }; + + m_GraphStateActions.Add(flagActions, recordingPassAndExecutingActions); + } + + // It's forbidden to use these APIs in RecordingGraph, RecordingPass and Executing mode. + void PopulateActiveGraphAPIActions() + { + var flagActions = RenderGraphState.Active; + var textureHandle = new TextureHandle(); + var activeGraphActions = new List + { + () => m_RenderGraph.Cleanup(), + () => m_RenderGraph.RegisterDebug(), + () => m_RenderGraph.UnRegisterDebug(), + () => m_RenderGraph.EndFrame(), + () => m_RenderGraph.BeginRecording(new RenderGraphParameters()), + () => m_RenderGraph.CreateSharedTexture(new TextureDesc()), + () => m_RenderGraph.ReleaseSharedTexture(textureHandle) + }; + + m_GraphStateActions.Add(flagActions, activeGraphActions); + } + + void ExecuteRenderGraphAPIActions(RenderGraphState state) + { + if (!m_GraphStateActions.ContainsKey(state)) + return; + + var listAPIs = m_GraphStateActions[state]; + var graphStateException = RenderGraph.RenderGraphExceptionMessages.GetExceptionMessage(state); + + foreach (var action in listAPIs) + { + // Clear the graph to avoid any previous state (invalid pass because we threw an exception during the setup of the pass). + m_RenderGraph.ClearCurrentCompiledGraph(); + + // Manually check the flag to avoid testing Idle and Active states. + if ((state & RenderGraphState.Executing) == RenderGraphState.Executing) + { + RecordGraphAPIError(RenderGraphState.Executing, graphStateException, action); + } + + if ((state & RenderGraphState.RecordingGraph) == RenderGraphState.RecordingGraph) + { + RecordGraphAPIError(RenderGraphState.RecordingGraph, graphStateException, action); + } + + if ((state & RenderGraphState.RecordingPass) == RenderGraphState.RecordingPass) + { + RecordGraphAPIError(RenderGraphState.RecordingPass, graphStateException, action); + } + } + } + + void RecordGraphAPIError(RenderGraphState graphState, string exceptionExpected, Action action) + { + m_RenderGraphTestPipeline.recordRenderGraphBody = (context, camera, cmd) => + { + if (graphState == RenderGraphState.RecordingGraph) + action.Invoke(); + + using (var builder = m_RenderGraph.AddRasterRenderPass("TestPass_APIRecordingError", out var passData)) + { + builder.AllowPassCulling(false); + + if (graphState == RenderGraphState.RecordingPass) + action.Invoke(); + + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => + { + if (graphState == RenderGraphState.Executing) + action.Invoke(); + }); + } + }; + + LogAssert.Expect(LogType.Error, RenderGraph.RenderGraphExceptionMessages.k_RenderGraphExecutionError); + LogAssert.Expect(LogType.Exception, k_InvalidOperationMessage + exceptionExpected); m_Camera.Render(); } diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs new file mode 100644 index 00000000..0afb70b6 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs @@ -0,0 +1,25 @@ +using UnityEditor; +using NUnit.Framework; +using UnityEditor.Rendering; + +namespace UnityEngine.Rendering.Tests +{ + class ScriptTemplatesTests + { + string[] paths = new string[] + { + $"{ScriptTemplates.ScriptTemplatePath}BlitSRP.txt" + }; + + [Test] + public void ScriptTemplatesExist() + { + for (int i = 0; i < paths.Length; i++) + { + var asset = AssetDatabase.LoadAssetAtPath(paths[i]); + + Assert.NotNull(asset); + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs.meta new file mode 100644 index 00000000..64b3abaf --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/ScriptTemplateTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3c34b238c5994e4aa5f4c044f75d850 diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs new file mode 100644 index 00000000..e472520e --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs @@ -0,0 +1,399 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace UnityEngine.Rendering.Utils.Tests +{ + [TestFixture] + class ObservableListTests + { + public static IEnumerable TestCasesAdd + { + get + { + yield return new TestCaseData((Action>)(list => list.Add(5)), (Comparison)((x, y) => x.CompareTo(y)), new [] {5}) + .SetName("AddOneElement_Sort"); + yield return new TestCaseData((Action>)(list => list.Add(5)), null, new [] {5}) + .SetName("AddOneElement"); + + yield return new TestCaseData((Action>)(list => + { + list.Add(3); + list.Add(1); + list.Add(4); + }), + (Comparison)((x, y) => x.CompareTo(y)), new [] {1, 3, 4}) + .SetName("AddMultipleELements_Sort"); + yield return new TestCaseData((Action>)(list => + { + list.Add(3); + list.Add(1); + list.Add(4); + }), null, new [] {3, 1, 4}) + .SetName("AddMultipleELements"); + + yield return new TestCaseData((Action>)( + list => list.Add(3, 1, 4)), (Comparison)((x, y) => x.CompareTo(y)), new [] {1, 3, 4}) + .SetName("AddMultipleElementsAtOnce_Sort"); + yield return new TestCaseData((Action>)( + list => list.Add(3, 1, 4)),null, new [] {3, 1, 4}) + .SetName("AddMultipleElementsAtOnce"); + } + } + + [Test, TestCaseSource(nameof(TestCasesAdd))] + public void Add_On_List(Action> modify, Comparison comparison, int[] expected) + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0, comparison: comparison); + bool itemAddedEventTriggered = false; + list.ItemAdded += (sender, args) => itemAddedEventTriggered = true; + + modify(list); + + // Assert + Assert.IsTrue(itemAddedEventTriggered); + Assert.AreEqual(expected.Length, list.Count); + for (int i = 0; i < expected.Length; i++) + { + Assert.AreEqual(expected[i], list[i]); + } + } + + public static IEnumerable TestCasesRemove + { + get + { + yield return new TestCaseData(new int[] {5, 1}, (Action>)(list => list.Remove(1)), (Comparison)((x, y) => x.CompareTo(y)), new [] {5}) + .SetName("RemoveOneElement_Sort"); + yield return new TestCaseData(new int[] {5, 1}, (Action>)(list => list.Remove(5)), null, new [] {1}) + .SetName("RemoveOneElement"); + + yield return new TestCaseData(new int[] {8,6,7,3,1,4},(Action>)(list => + { + list.Remove(3); + list.Remove(1); + list.Remove(4); + }), + (Comparison)((x, y) => x.CompareTo(y)), new [] {6, 7, 8}) + .SetName("RemoveMultipleElements_Sort"); + yield return new TestCaseData(new int[] {8,6,7,3,1,4},(Action>)(list => + { + list.Remove(3); + list.Remove(1); + list.Remove(4); + }), + null, new [] {8, 6, 7}) + .SetName("RemoveMultipleElements"); + + yield return new TestCaseData(new int[] {5, 1}, (Action>)(list => list.RemoveAt(0)), (Comparison)((x, y) => x.CompareTo(y)), new [] {5}) + .SetName("RemoveAtOneElement_Sort"); + yield return new TestCaseData(new int[] {5, 1}, (Action>)(list => list.RemoveAt(0)), null, new [] {1}) + .SetName("RemoveAtOneElement"); + + yield return new TestCaseData(new int[] {8,6,7,3,1,4},(Action>)(list => + { + list.RemoveAt(0); + list.RemoveAt(1); + list.RemoveAt(2); + }), + (Comparison)((x, y) => x.CompareTo(y)), new [] {3, 6, 8}) + .SetName("RemoveAtMultipleElements_Sort"); + yield return new TestCaseData(new int[] {8,6,7,3,1,4},(Action>)(list => + { + list.RemoveAt(0); + list.RemoveAt(1); + list.RemoveAt(2); + }), + null, new [] {6, 3, 4}) + .SetName("RemoveAtMultipleElements"); + } + } + + [Test, TestCaseSource(nameof(TestCasesRemove))] + public void Remove_From_List(int[] init, Action> modify, Comparison comparison, int[] expected) + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(init, comparison: comparison); + bool itemRemovedTriggered = false; + list.ItemRemoved += (sender, args) => itemRemovedTriggered = true; + + modify(list); + + // Assert + Assert.IsTrue(itemRemovedTriggered); + Assert.AreEqual(expected.Length, list.Count); + for (int i = 0; i < expected.Length; i++) + { + Assert.AreEqual(expected[i], list[i]); + } + } + + public static IEnumerable TestCasesInsert + { + get + { + yield return new TestCaseData(new int[] {}, (Action>)(list => list.Insert(0, 1)), (Comparison)((x, y) => x.CompareTo(y)), new [] {1}) + .SetName("InsertOneElement_Sort"); + yield return new TestCaseData(new int[] {}, (Action>)(list => list.Insert(0, 1)), null, new [] {1}) + .SetName("InsertOneElement"); + + yield return new TestCaseData(new int[] {8,6,7},(Action>)(list => + { + list.Insert(0, 3); + list.Insert(0, 10); + list.Insert(0, 2); + }), + (Comparison)((x, y) => x.CompareTo(y)), new [] {2, 3, 6, 7, 8, 10}) + .SetName("InsertultipleElements_Sort"); + yield return new TestCaseData(new int[] {8,6,7},(Action>)(list => + { + list.Insert(0, 0); + list.Insert(0, 10); + }), + null, new [] {10, 0, 8, 6, 7}) + .SetName("InsertMultipleElements"); + } + } + + [Test, TestCaseSource(nameof(TestCasesInsert))] + public void Insert_Into_List(int[] init, Action> modify, Comparison comparison, int[] expected) + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(init, comparison: comparison); + bool itemRemovedTriggered = false; + list.ItemAdded += (sender, args) => itemRemovedTriggered = true; + + modify(list); + + // Assert + Assert.IsTrue(itemRemovedTriggered); + Assert.AreEqual(expected.Length, list.Count); + for (int i = 0; i < expected.Length; i++) + { + Assert.AreEqual(expected[i], list[i]); + } + } + + // Test for clearing the list + [Test] + public void Clear_ClearsList_ItemRemovedEventTriggeredForEach_NoComparison() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0, comparison: (x, y) => x.CompareTo(y)); + list.Add(5); + list.Add(10); + bool itemRemovedEventTriggered = false; + list.ItemRemoved += (sender, args) => itemRemovedEventTriggered = true; + + // Act + list.Clear(); + + // Assert + Assert.AreEqual(0, list.Count); + Assert.IsTrue(itemRemovedEventTriggered); + } + + // Test for indexer getting and setting an item + [Test] + public void SetIndexer_SetsItem_TriggersEvents() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0,comparison: (x, y) => x.CompareTo(y)); + list.Add(1); + list.Add(2); + bool itemAddedEventTriggered = false; + bool itemRemovedEventTriggered = false; + list.ItemAdded += (sender, args) => itemAddedEventTriggered = true; + list.ItemRemoved += (sender, args) => itemRemovedEventTriggered = true; + + // Act + list[0] = 5; + + // Assert + Assert.AreEqual(2, list.Count); + Assert.AreEqual(5, list[0]); + Assert.IsTrue(itemAddedEventTriggered); + Assert.IsTrue(itemRemovedEventTriggered); + } + + // Test for Contains method + [Test] + public void Contains_ReturnsTrueIfItemExists() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0,comparison: (x, y) => x.CompareTo(y)); + list.Add(5); + + // Act + bool result = list.Contains(5); + + // Assert + Assert.IsTrue(result); + } + + // Test for IndexOf method + [Test] + public void IndexOf_ReturnsCorrectIndex() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0, comparison: (x, y) => x.CompareTo(y)); + list.Add(5); + list.Add(10); + + // Act + int index = list.IndexOf(10); + + // Assert + Assert.AreEqual(1, index); + } + + // Test for constructor with collection and custom comparison + [Test] + public void ConstructorWithCollection_SortsItems_WhenComparisonProvided() + { + // Arrange + var collection = new List { 3, 1, 2 }; + var list = new UnityEngine.Rendering.ObservableList(collection, comparison: (x, y) => x.CompareTo(y)); + + // Assert + Assert.AreEqual(3, list.Count); + Assert.AreEqual(1, list[0]); + Assert.AreEqual(2, list[1]); + Assert.AreEqual(3, list[2]); + } + + // Test for constructor with custom comparison and sorting + [Test] + public void ConstructorWithComparison_SortsItems_WhenComparisonProvided() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(0,comparison: (x, y) => x.CompareTo(y)); + + // Act + list.Add(10); + list.Add(5); + list.Add(7); + + // Assert + Assert.AreEqual(3, list.Count); + Assert.AreEqual(5, list[0]); + Assert.AreEqual(7, list[1]); + Assert.AreEqual(10, list[2]); + } + + // Test for inserting an item at a specific index without comparison + [Test] + public void InsertsItemAtIndex_ItemAddedEventTriggered_NoComparison() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(1); // Ensure there is at least one item + bool itemAddedEventTriggered = false; + list.ItemAdded += (sender, args) => itemAddedEventTriggered = true; + + // Act + list.Insert(1, 5); // Insert 5 at the end + + // Assert + Assert.AreEqual(2, list.Count); + Assert.IsTrue(itemAddedEventTriggered); + Assert.AreEqual(5, list[1]); // Verify that 5 is inserted at index 1 + } + + // Test for inserting an item at the beginning + [Test] + public void InsertsItemAtBeginning_ItemAddedEventTriggered() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(10); // Ensure there is at least one item + bool itemAddedEventTriggered = false; + list.ItemAdded += (sender, args) => itemAddedEventTriggered = true; + + // Act + list.Insert(0, 5); // Insert 5 at the beginning + + // Assert + Assert.AreEqual(2, list.Count); + Assert.IsTrue(itemAddedEventTriggered); + Assert.AreEqual(5, list[0]); // Verify that 5 is inserted at index 0 + } + + // Test for inserting an item at an index greater than the last item index + [Test] + public void InsertsItemAtOutOfRangeIndex_ItemAddedEventTriggered() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + Assert.Throws(() => list.Insert(10, 5)); // Inserting at an index greater than the list size + } + + // Test for removing an item that doesn't exist + [Test] + public void Remove_ItemNotInList_ReturnsFalse() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(10); + list.Add(20); + + // Act + bool result = list.Remove(30); // 30 is not in the list + + // Assert + Assert.AreEqual(2, list.Count); // List should remain unchanged + Assert.IsFalse(result); // Removal should fail + } + + // Test for removing an item that doesn't exist using RemoveAt + [Test] + public void RemoveAt_IndexOutOfRange_ThrowsException() + { + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(10); + + Assert.Throws(() => list.RemoveAt(10)); // Trying to remove from an invalid index + } + + // Test for inserting multiple items (with no comparison) + [Test] + public void InsertMultiple_AddsItemsAtSpecificIndex_ItemAddedEventTriggeredForEach() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(10); + list.Add(20); + bool itemAddedEventTriggered = false; + list.ItemAdded += (sender, args) => itemAddedEventTriggered = true; + + // Act + list.Insert(1, 15); // Insert 15 at index 1 + + // Assert + Assert.AreEqual(3, list.Count); + Assert.IsTrue(itemAddedEventTriggered); + Assert.AreEqual(15, list[1]); // 15 should be inserted at index 1 + } + + // Test for clearing the list + [Test] + public void Clear_ClearsList_ItemRemovedEventTriggeredForEach() + { + // Arrange + var list = new UnityEngine.Rendering.ObservableList(); + list.Add(10); + list.Add(20); + bool itemRemovedEventTriggered = false; + list.ItemRemoved += (sender, args) => itemRemovedEventTriggered = true; + + // Act + list.Clear(); + + // Assert + Assert.AreEqual(0, list.Count); + Assert.IsTrue(itemRemovedEventTriggered); // Events should trigger for every item removed + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs.meta new file mode 100644 index 00000000..8403a2bc --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Utilities/ObservableListTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2fe1182006044321a72f6e5bd11ceb1d +timeCreated: 1736434600 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs deleted file mode 100644 index f1949595..00000000 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs +++ /dev/null @@ -1,20 +0,0 @@ -using NUnit.Framework; - -namespace UnityEngine.Rendering.Tests -{ - class ObservableListTests - { - [Test] - public void ObservableList_CompletelyCleared() - { - var observableList = new ObservableList(); - - for(int i = 0; i < 5; i++) - observableList.Add(i); - - observableList.Clear(); - Assert.AreEqual(0, observableList.Count, - $"{observableList.Count} elements remaining after ObservableList.Clear(), expected 0"); - } - } -} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs.meta deleted file mode 100644 index 7c1541cb..00000000 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/ObservableListTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2780ee2706314f0cbc1d7ea5483ffea6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeExampleTest.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeExampleTest.cs index e08ffec2..a697d48d 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeExampleTest.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeExampleTest.cs @@ -14,6 +14,7 @@ class RuntimeExampleTest // A UnityTest behaves like a coroutine in PlayMode // and allows you to yield null to skip a frame in EditMode [UnityTest] + [Ignore("Unstable: https://jira.unity3d.com/browse/UUM-102848")] public IEnumerator PlayModeSampleTestWithEnumeratorPasses() { // Use the Assert class to test conditions. diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs index 1543e270..ee29f1ed 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs @@ -55,11 +55,10 @@ namespace UnityEngine.Rendering.Tests } } - // Fails on WebGL, Oculus Quest and Embedded Platforms (GLES3). + // Fails on WebGL, Oculus Quest and Switch. // Unfortunately, there is no good way to exclude Oculus Quest from the test without excluding all Android devices. // https://jira.unity3d.com/browse/GFXFOUND-559 - // https://jira.unity3d.com/browse/PLAT-13842 (GLES3 gpuFrameTime is currently only available on Android) - [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android, RuntimePlatform.EmbeddedLinuxArm64 })] + [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android, RuntimePlatform.Switch })] class RuntimeProfilerTests : RuntimeProfilerTestBase { [UnityTest] diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/Threading/FunctionTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/Threading/FunctionTests.cs index 703ddd0b..3023fb5a 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/Threading/FunctionTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/Threading/FunctionTests.cs @@ -170,6 +170,15 @@ class ThreadingEmulationFunctionTests : IPrebuildSetup Assert.Ignore($"The device's max compute group size X dimension ({deviceMaxComputeGroupSizeX}) does not meet the minimum requirement ({requiredComputeGroupSizeX}) for this test"); } + [SetUp] + public void SetupIgnores() + { + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.WebGPU) + { + Assert.Ignore("These tests are not supported on WebGPU"); + } + } + [Test] [UnityPlatform(exclude = new[] { RuntimePlatform.WindowsEditor, RuntimePlatform.WSAPlayerX64, RuntimePlatform.WindowsPlayer })] //https://jira.unity3d.com/browse/UUM-78016 public void WaveTest([Values]Kernel kernel, [Values]WaveSizeKeyword waveSizeKeyword) diff --git a/Packages/com.unity.render-pipelines.core/package.json b/Packages/com.unity.render-pipelines.core/package.json index 8e9bebb6..ae301b0c 100644 --- a/Packages/com.unity.render-pipelines.core/package.json +++ b/Packages/com.unity.render-pipelines.core/package.json @@ -1,8 +1,8 @@ { "name": "com.unity.render-pipelines.core", "description": "SRP Core makes it easier to create or customize a Scriptable Render Pipeline (SRP). SRP Core contains reusable code, including boilerplate code for working with platform-specific graphics APIs, utility functions for common rendering operations, and shader libraries. The code in SRP Core is use by the High Definition Render Pipeline (HDRP) and Universal Render Pipeline (URP). If you are creating a custom SRP from scratch or customizing a prebuilt SRP, using SRP Core will save you time.", - "version": "17.1.0", - "unity": "6000.1", + "version": "17.2.0", + "unity": "6000.2", "displayName": "Scriptable Render Pipeline Core", "dependencies": { "com.unity.burst": "1.8.14", @@ -14,5 +14,5 @@ "com.unity.modules.jsonserialize": "1.0.0", "com.unity.rendering.light-transport": "1.0.1" }, - "_fingerprint": "943f3af6fe14719bad5cae2cf73687f86e685e1b" + "_fingerprint": "bd0e8186c2bcfea109ee5981b813a1b39a6382fb" } diff --git a/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md b/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md index bce83452..a0522f23 100644 --- a/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md @@ -12,7 +12,7 @@ The version number for this package has increased due to a version update of a r ## [17.0.3] - 2025-02-13 -This version is compatible with Unity 6000.2.0a1. +This version is compatible with Unity 6000.2.0a5 Version Updated The version number for this package has increased due to a version update of a related graphics package. diff --git a/Packages/com.unity.render-pipelines.high-definition-config/package.json b/Packages/com.unity.render-pipelines.high-definition-config/package.json index d080c346..2bb29f30 100644 --- a/Packages/com.unity.render-pipelines.high-definition-config/package.json +++ b/Packages/com.unity.render-pipelines.high-definition-config/package.json @@ -1,11 +1,11 @@ { "name": "com.unity.render-pipelines.high-definition-config", "description": "Configuration files for the High Definition Render Pipeline.", - "version": "17.1.0", - "unity": "6000.1", + "version": "17.2.0", + "unity": "6000.2", "displayName": "High Definition Render Pipeline Config", "dependencies": { - "com.unity.render-pipelines.core": "17.1.0" + "com.unity.render-pipelines.core": "17.2.0" }, - "_fingerprint": "8c699487ee0c5bb938902fb2e91075c921a1fb5f" + "_fingerprint": "f7c893e8c254a6aa8b789a59d79275671ed7d3b9" } diff --git a/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md b/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md index b86905bc..426c3bc6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -12,9 +12,11 @@ The version number for this package has increased due to a version update of a r ## [17.0.3] - 2025-02-13 -This version is compatible with Unity 6000.2.0a1. +This version is compatible with Unity 6000.2.0a5. ### Changed +- Rendering Debugger - Moved decals to the Rendering Section. +- Rendering Debugger - Moved lighting HDR settings to the Rendering Section. - Wizard - Simplified the list of validations for IRenderPipelineGraphicsSettings. - Improved the water sample by adding a cave scene using caustics and deformation texture. - Improved Depth usage performance for some platforms. @@ -31,6 +33,16 @@ This version is compatible with Unity 6000.2.0a1. - Improved water sample by adding a cave scene using caustics and deformation texture. ### Fixed +- Fixed the macro redefinition warnings that occur in Lit.shader and HDShadowAlgorithms.hlsl, by implement a check to see if PUNCTUAL_SHADOW_LOW, USE_FPTL_LIGHTLIST and DIRECTIONAL_SHADOW_LOW have already been previously defined. (UUM-83878) +- Fixed High Definition Render Pipeline's Wizard to no longer assume a check fail while waiting a reply from the Package Manager and will display a specific pending icon. +- Fixed an issue where the padding in the Lighting window was different between tabs. +- Fixed artifacts when blending cascade shadows and distance shadowmask. +- Fix Sensor SDK related compilation issue on DXR-enabled HDRP projects. +- Improved the error message when fog volumes on screen exceed the limit. Emit this error message only in editor and development builds. +- Fix a missing attenuation of the albedo when converting the decal albedo + metal into specular color. +- Rendering Debugger - Frame Settings - Adding 1 single panel for all cameras instead of having 1 panel per camera in the debugger. +- Fix underwater collider bounds check to be accurate when the collider is rotated +- Fixed rendering a black ground when opening a new HDRP scene. - Fixed layer index out of range in LayeredLitGUI. - Fixed advanced upsampler settings not visible on platforms where they are not supported. - Fixed cloud layers not being drawn behind transparent refractive objects. diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Skin.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Skin.cs index 0adcc91f..6efdb7cb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Skin.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDProbeUI.Skin.cs @@ -28,10 +28,10 @@ namespace UnityEditor.Rendering.HighDefinition static readonly Dictionary k_ToolbarContents = new Dictionary { - { ToolBar.InfluenceShape, EditorGUIUtility.TrIconContent("EditCollider", "Modify the base shape.") }, - { ToolBar.Blend, EditorGUIUtility.TrIconContent("PreMatCube", "Modify the influence volume.") }, - { ToolBar.NormalBlend, EditorGUIUtility.TrIconContent("SceneViewOrtho", "Modify the influence normal volume.") }, - { ToolBar.CapturePosition, EditorGUIUtility.TrIconContent("MoveTool", "Change the capture position.") }, + { ToolBar.InfluenceShape, EditorGUIUtility.TrIconContent("EditShape", "Modify the base shape.") }, + { ToolBar.Blend, EditorGUIUtility.TrIconContent("BlendDistance", "Modify the influence volume blend distance.") }, + { ToolBar.NormalBlend, EditorGUIUtility.TrIconContent("NormalBlendDistance", "Modify the influence volume normal blend distance.") }, + { ToolBar.CapturePosition, EditorGUIUtility.TrIconContent("CapturePosition", "Change the capture position.") }, { ToolBar.MirrorPosition, EditorGUIUtility.TrIconContent("MoveTool", "Change the mirror position.") }, { ToolBar.MirrorRotation, EditorGUIUtility.TrIconContent("RotateTool", "Change the mirror rotation.") }, { ToolBar.ShowChromeGizmo, EditorGUIUtility.TrIconContent(IconReflectionProbeGizmoId, "Display the chrome gizmo.") }, diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs index d2d32589..059f430a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDScreenSpaceReflectionEditor.cs @@ -45,6 +45,7 @@ namespace UnityEditor.Rendering.HighDefinition SerializedDataParameter m_DenoiserRadius; SerializedDataParameter m_DenoiserAntiFlickeringStrength; SerializedDataParameter m_Mode; + SerializedDataParameter m_APVMask; // Mixed SerializedDataParameter m_RayMaxIterationsRT; @@ -95,6 +96,7 @@ namespace UnityEditor.Rendering.HighDefinition m_DenoiserRadius = Unpack(o.Find(x => x.denoiserRadius)); m_DenoiserAntiFlickeringStrength = Unpack(o.Find(x => x.denoiserAntiFlickeringStrength)); m_Mode = Unpack(o.Find(x => x.mode)); + m_APVMask = Unpack(o.Find(x => x.adaptiveProbeVolumesLayerMask)); // Mixed m_RayMaxIterationsRT = Unpack(o.Find(x => x.rayMaxIterationsRT)); @@ -243,6 +245,9 @@ namespace UnityEditor.Rendering.HighDefinition { RayTracingPerformanceModeGUI(tracingMode == RayCastingMode.Mixed); } + + if (currentAsset?.currentPlatformRenderPipelineSettings.lightProbeSystem == RenderPipelineSettings.LightProbeSystem.AdaptiveProbeVolumes) + PropertyField(m_APVMask); } public override void OnInspectorGUI() 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 index 44ad1219..5290ae33 100644 --- 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 @@ -32,5 +32,5 @@ float4x4 BuildWorldToObjectMatrixFromLocalFogOBB() float3 TransformWorldToObjectFog(float3 positionRWS) { float3 posWS = GetAbsolutePositionWS(positionRWS); - return mul(BuildWorldToObjectMatrixFromLocalFogOBB(), float4(posWS, 1)).xyz; + return mul(BuildWorldToObjectMatrixFromLocalFogOBB(), float4(posWS, 1)); } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/LayeredLit/LayeredLitGUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/LayeredLit/LayeredLitGUI.cs index d6487472..34fa6324 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/LayeredLit/LayeredLitGUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/LayeredLit/LayeredLitGUI.cs @@ -76,36 +76,36 @@ namespace UnityEditor.Rendering.HighDefinition if (layerMaterial != null) { Shader layerShader = layerMaterial.shader; - int propertyCount = ShaderUtil.GetPropertyCount(layerShader); + int propertyCount = layerShader.GetPropertyCount(); for (int i = 0; i < propertyCount; ++i) { - string propertyName = ShaderUtil.GetPropertyName(layerShader, i); + string propertyName = layerShader.GetPropertyName(i); string layerPropertyName = propertyName + layerIndex; if (includeUVMappingProperties || !exclusionList.Contains(propertyName)) { if (material.HasProperty(layerPropertyName)) { - ShaderUtil.ShaderPropertyType type = ShaderUtil.GetPropertyType(layerShader, i); + ShaderPropertyType type = layerShader.GetPropertyType(i); switch (type) { - case ShaderUtil.ShaderPropertyType.Color: + case ShaderPropertyType.Color: { material.SetColor(layerPropertyName, layerMaterial.GetColor(propertyName)); break; } - case ShaderUtil.ShaderPropertyType.Float: - case ShaderUtil.ShaderPropertyType.Range: + case ShaderPropertyType.Float: + case ShaderPropertyType.Range: { material.SetFloat(layerPropertyName, layerMaterial.GetFloat(propertyName)); break; } - case ShaderUtil.ShaderPropertyType.Vector: + case ShaderPropertyType.Vector: { material.SetVector(layerPropertyName, layerMaterial.GetVector(propertyName)); break; } - case ShaderUtil.ShaderPropertyType.TexEnv: + case ShaderPropertyType.Texture: { material.SetTexture(layerPropertyName, layerMaterial.GetTexture(propertyName)); if (includeUVMappingProperties) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/HDSixWaySubTarget.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/HDSixWaySubTarget.cs index 4452dd42..75fa714a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/HDSixWaySubTarget.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/HDSixWaySubTarget.cs @@ -61,7 +61,6 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph requiredFields.Add(CoreRequiredFields.BasicLighting); requiredFields.Add(SixWayStructs.RequiredFields); - DefineCollection defines = HDShaderPasses.GenerateDefines(CoreDefines.Forward, useVFX, useTessellation); if (useColorAbsorption) @@ -151,6 +150,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph public static FieldCollection RequiredFields = new FieldCollection() { + StructFields.SurfaceDescriptionInputs.FaceSign, SixWayVaryings.diffuseGIData0, SixWayVaryings.diffuseGIData1, SixWayVaryings.diffuseGIData2, @@ -187,7 +187,7 @@ namespace UnityEditor.Rendering.HighDefinition.ShaderGraph "VARYINGS_NEED_SIX_WAY_DIFFUSE_GI_DATA", ShaderValueType.Float4, subscriptOptions: StructFieldOptions.Optional); public static FieldDescriptor[] AllFragInputs = new FieldDescriptor[] - { diffuseGIData0, diffuseGIData1, diffuseGIData2 }; + { StructFields.Varyings.cullFace, diffuseGIData0, diffuseGIData1, diffuseGIData2 }; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/ShaderPass.template.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/ShaderPass.template.hlsl index f74f05f6..0404417c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/ShaderPass.template.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/ShaderGraph/ShaderPass.template.hlsl @@ -14,17 +14,14 @@ void BuildSurfaceData(FragInputs fragInputs, inout SurfaceDescription surfaceDes $FragInputs.diffuseGIData1: surfaceData.bakeDiffuseLighting1 = fragInputs.diffuseGIData[1]; $FragInputs.diffuseGIData2: surfaceData.bakeDiffuseLighting2 = fragInputs.diffuseGIData[2]; - float3 doubleSidedConstants = GetDoubleSidedConstants(); - - GetNormalWS(fragInputs, float3(0,0,1), surfaceData.normalWS, doubleSidedConstants); + float frontFaceSign = fragInputs.isFrontFace ? 1.0f : -1.0f; surfaceData.tangentWS = float4(normalize(fragInputs.tangentToWorld[0].xyz), 1); - #ifdef _DOUBLESIDED_ON - float tangentSign = fragInputs.isFrontFace ? 1.0f : -1.0f; - #else - float tangentSign = 1.0f; - #endif - surfaceData.tangentWS = float4(Orthonormalize(surfaceData.tangentWS.xyz, surfaceData.normalWS), tangentSign); + surfaceData.bitangentWS = fragInputs.tangentToWorld[1].xyz; + surfaceData.normalWS = frontFaceSign * fragInputs.tangentToWorld[2].xyz; + + surfaceData.bakeDiffuseLighting2.xyz *= frontFaceSign; + bentNormalWS = surfaceData.normalWS; //Not used #ifdef DEBUG_DISPLAY diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/SixWayGUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/SixWayGUI.cs index 5d8f37f2..00d5b343 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/SixWayGUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/SixWayLit/SixWayGUI.cs @@ -16,7 +16,7 @@ namespace UnityEditor.Rendering.HighDefinition { MaterialUIBlockList m_UIBlocks = new() { - new SurfaceOptionUIBlock(MaterialUIBlock.ExpandableBit.Base,1, SurfaceOptionUIBlock.Features.Lit), + new SurfaceOptionUIBlock(MaterialUIBlock.ExpandableBit.Base,1, (SurfaceOptionUIBlock.Features.Lit | SurfaceOptionUIBlock.Features.ShowDepthOffsetOnly) ^ SurfaceOptionUIBlock.Features.DoubleSidedNormalMode ^ SurfaceOptionUIBlock.Features.PreserveSpecularLighting), new SixWayUIBlock(MaterialUIBlock.ExpandableBit.Base), new TessellationOptionsUIBlock(MaterialUIBlock.ExpandableBit.Tessellation), new ShaderGraphUIBlock(MaterialUIBlock.ExpandableBit.ShaderGraph, ShaderGraphUIBlock.Features.ExposedProperties), diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/ShaderGraphUIBlock.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/ShaderGraphUIBlock.cs index fff2793c..0834b9e9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/ShaderGraphUIBlock.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/ShaderGraphUIBlock.cs @@ -72,11 +72,11 @@ namespace UnityEditor.Rendering.HighDefinition { for (int i = 0; i < properties.Length; i++) { - if (properties[i].type != oldProperties[i].type) + if (properties[i].propertyType != oldProperties[i].propertyType) propertyChanged = true; if (properties[i].displayName != oldProperties[i].displayName) propertyChanged = true; - if (properties[i].flags != oldProperties[i].flags) + if (properties[i].propertyFlags != oldProperties[i].propertyFlags) propertyChanged = true; if (properties[i].name != oldProperties[i].name) propertyChanged = true; diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/SurfaceOptionUIBlock.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/SurfaceOptionUIBlock.cs index 4035bc60..0068fdaf 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/SurfaceOptionUIBlock.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/UIBlocks/SurfaceOptionUIBlock.cs @@ -122,7 +122,7 @@ namespace UnityEditor.Rendering.HighDefinition public static GUIContent lockWithTilingRateText = new GUIContent("Lock With Height Map Tiling Rate", "When enabled, displacement mapping takes the absolute value of the tiling rate of the height map into account."); // Material ID - public static GUIContent materialIDText = new GUIContent("Material Type", "Specifies additional feature for this Material. Customize you Material with different settings depending on which Material Type you select."); + public static GUIContent materialIDText = new GUIContent("Material Type", "Specifies additional features for this Material. Customize your Material with different settings depending on which Material Type you select."); public static GUIContent transmissionEnableText = new GUIContent("Transmission", "When enabled HDRP processes the transmission effect for subsurface scattering. Simulates the translucency of the object."); public static string transparentSSSErrorMessage = "Transparent Materials With SubSurface Scattering is not supported."; public static GUIContent clearCoatEnabledText = new GUIContent("Clear Coat", "Controls whether the clear coat effect is enabled or not."); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDEditorUtils.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDEditorUtils.cs index d0162da1..4a0916a3 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDEditorUtils.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDEditorUtils.cs @@ -386,16 +386,25 @@ namespace UnityEditor.Rendering.HighDefinition bool disabledByDefault = !defaultValue && !cameraOverrideState; bool disabledByCameraOverride = cameraOverrideState && !cameraOverridenValue; - - var textBase = $"The FrameSetting required to render this effect in the {(camera.cameraType == CameraType.SceneView ? "Scene" : "Game")} view (by {camera.name}) "; + + // If the setting is enabled in the frame settings but is disabled in the HDRP Asset (cameraSanitizedValue), it means the feature is disabled and we should not display anything. + bool disabledbySanitized = (cameraOverrideState ? cameraOverridenValue : defaultValue) && !cameraSanitizedValue; + + var textBase = $"The Frame Setting required to render this effect in the {(camera.cameraType == CameraType.SceneView ? "Scene" : "Game")} view "; if (disabledByDefault) - GlobalSettingsHelpBox(textBase + "is disabled in the HDRP Global Settings.", MessageType.Warning, field, attribute.displayedName); + GlobalSettingsHelpBox(textBase + "is disabled in the HDRP Default Frame Settings.", MessageType.Warning, field, attribute.displayedName); else if (disabledByCameraOverride) - CoreEditorUtils.DrawFixMeBox(textBase + $"is disabled on the Camera.", MessageType.Warning, "Open", () => EditorUtility.OpenPropertyEditor(camera)); + CoreEditorUtils.DrawFixMeBox(textBase + $"is disabled in the {camera.name}'s Custom Frame Settings.", MessageType.Warning, "Open", () => EditorUtility.OpenPropertyEditor(camera)); else if (!dependenciesSanitizedValueOk) - GlobalSettingsHelpBox(textBase + "depends on a disabled FrameSetting.", MessageType.Warning, field, attribute.displayedName); - else if (!finalValue) + { + if(cameraOverrideState) + CoreEditorUtils.DrawFixMeBox(textBase + $"depends on a disabled Frame Setting parent in the {camera.name} Custom Frame Settings.", MessageType.Warning, "Open", () => EditorUtility.OpenPropertyEditor(camera)); + else + GlobalSettingsHelpBox(textBase + "depends on a disabled Frame Setting parent in the HDRP Default Frame Settings.", MessageType.Warning, field, attribute.displayedName); + + } + else if (!finalValue && !disabledbySanitized) CoreEditorUtils.DrawFixMeBox(textBase + "is disabled in the Rendering Debugger.", MessageType.Warning, "Open", () => HighlightInDebugger(camera, field, attribute.displayedName)); } @@ -417,7 +426,7 @@ namespace UnityEditor.Rendering.HighDefinition static IEnumerable<(Camera camera, T component)> SelectVolumeComponent(IEnumerable cameras) where T : VolumeComponent { // Wait for volume system to be initialized - if (VolumeManager.instance.baseComponentTypeArray == null) + if (!VolumeManager.instance.isInitialized) yield break; foreach (var camera in GetAllCameras()) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs index 409355f1..7826d49e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs @@ -183,7 +183,6 @@ namespace UnityEditor.Rendering.HighDefinition public static readonly GUIContent supportRaytracing = EditorGUIUtility.TrTextContent("Realtime Raytracing"); public static readonly GUIContent supportedRayTracingMode = EditorGUIUtility.TrTextContent("Supported Ray Tracing Mode"); public static readonly GUIContent supportVFXRayTracing = EditorGUIUtility.TrTextContent("Visual Effects Ray Tracing", "When enabled, Visual Effects Outputs which have Enable Ray Tracing on will be accounted for in Ray-traced effects."); - public static readonly GUIContent rayTracingUnsupportedWarning = EditorGUIUtility.TrTextContent("Ray tracing is not supported on your device. Please refer to the documentation."); public static readonly GUIContent rayTracingRestrictionOnlyWarning = EditorGUIUtility.TrTextContent("Ray tracing is currently only supported on DX12, Playstation 5 and Xbox Series X.", null, CoreEditorStyles.iconWarn); public static readonly GUIContent rayTracingMSAAUnsupported = EditorGUIUtility.TrTextContent("When Ray tracing is enabled in asset, MSAA is not supported. Please refer to the documentation."); public static readonly GUIContent waterMSAAUnsupported = EditorGUIUtility.TrTextContent("When Water is enabled in asset, MSAA is not supported. Please refer to the documentation."); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index 2fe854b4..f81c76ca 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -1299,8 +1299,6 @@ namespace UnityEditor.Rendering.HighDefinition { if (serialized.renderPipelineSettings.supportRayTracing.boolValue) DisplayRayTracingSupportBox(); - else - EditorGUILayout.HelpBox(Styles.rayTracingUnsupportedWarning.text, MessageType.Warning, wide: true); } --EditorGUI.indentLevel; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/USS/FrameSettings.uss b/Packages/com.unity.render-pipelines.high-definition/Editor/USS/FrameSettings.uss index 0fdd4bcf..c5e5d7a8 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/USS/FrameSettings.uss +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/USS/FrameSettings.uss @@ -58,3 +58,19 @@ { background-color: var(--unity-colors-helpbox-background); } + +.header-foldout +{ + margin: 0px -6px 0px -31px; + padding: 0px 0px 0px 0px; +} + +.unity-foldout__toggle +{ + padding: 0px 6px 0px 30px; +} + +.unity-foldout__content +{ + margin: 0px 5px 0px 47px; +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template index 677c8516..ad41610c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template @@ -16,7 +16,7 @@ ${VFXEnd} ${VFXBegin:VFXVertexProbeFillVaryings} #if VFX_MATERIAL_TYPE_SIX_WAY_SMOKE #if VFX_PRIMITIVE_QUAD || VFX_PRIMITIVE_TRIANGLE || VFX_PRIMITIVE_OCTAGON -float4 inTangent = float4(o.VFX_VARYING_TANGENT, 1.0f); +float4 inTangent = float4(o.VFX_VARYING_TANGENT, -1.0f); #else float4 inTangent = o.VFX_VARYING_TANGENT; #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/UIBlocks/VFXShaderGraphGUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/UIBlocks/VFXShaderGraphGUI.cs index f03e8bf0..5cee3117 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/UIBlocks/VFXShaderGraphGUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/UIBlocks/VFXShaderGraphGUI.cs @@ -35,8 +35,7 @@ namespace UnityEditor.Rendering.HighDefinition internal class VFXShaderGraphGUISixWay : SixWayGUI { - const SurfaceOptionUIBlock.Features vfxSurfaceOptionFeatures = SurfaceOptionUIBlock.Features.Lit - | SurfaceOptionUIBlock.Features.ShowDepthOffsetOnly ^ SurfaceOptionUIBlock.Features.PreserveSpecularLighting; + const SurfaceOptionUIBlock.Features vfxSurfaceOptionFeatures = (SurfaceOptionUIBlock.Features.Lit | SurfaceOptionUIBlock.Features.ShowDepthOffsetOnly) ^ SurfaceOptionUIBlock.Features.DoubleSidedNormalMode ^ SurfaceOptionUIBlock.Features.PreserveSpecularLighting; public VFXShaderGraphGUISixWay() { diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UIElement.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UIElement.cs index a4cab89d..a85636e2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UIElement.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UIElement.cs @@ -400,7 +400,6 @@ namespace UnityEditor.Rendering.HighDefinition var foldout = new HeaderFoldout { text = label, - tooltip = tooltip, documentationURL = DocumentationInfo.GetPageLink(Documentation.packageName, $"Render-Pipeline-Wizard", $"{mode}Tab") }; @@ -432,6 +431,7 @@ namespace UnityEditor.Rendering.HighDefinition foldout.value = HDUserSettings.IsOpen(mode); foldout.RegisterValueChangedCallback(evt => HDUserSettings.SetOpen(mode, evt.newValue)); + foldout.Q(className: "header-foldout__label").tooltip = tooltip; // Tooltip on the label to ensure the position doesn't change when opening the foldout Add(foldout); } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.Window.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.Window.cs index 787648d8..31eefa61 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.Window.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.Window.cs @@ -450,7 +450,9 @@ namespace UnityEditor.Rendering.HighDefinition if (MaterialUpgrader.ProjectFolderContainsNonBuiltinMaterials( UpgradeStandardShaderMaterials.GetHDUpgraders())) { - container.Add(new HelpBox(Style.nonBuiltinMaterialWarning, HelpBoxMessageType.Warning)); + var nonBuiltinMaterialHelpBox = new HelpBox(Style.nonBuiltinMaterialWarning, HelpBoxMessageType.Warning); + nonBuiltinMaterialHelpBox.AddToClassList("NonBuiltinMaterialWarning"); + container.Add(nonBuiltinMaterialHelpBox); } container.Add(CreateLargeButton(Style.migrateAllButton, UpgradeStandardShaderMaterials.UpgradeMaterialsProject)); @@ -524,6 +526,7 @@ namespace UnityEditor.Rendering.HighDefinition UpdateDisplayOfConfigPackageArea(ConfigPackageState.Present)); }); m_InstallConfigPackageHelpbox = new HelpBox(Style.installConfigPackageInfoInCheck, HelpBoxMessageType.Info); + m_InstallConfigPackageHelpbox.AddToClassList("InstallConfigPackageMessage"); m_InstallConfigPackageHelpboxLabel = m_InstallConfigPackageHelpbox.Q(); area.Add(m_InstallConfigPackageButton); area.Add(m_InstallConfigPackageHelpbox); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/USS/Wizard.uss b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/USS/Wizard.uss index d1871ce6..87c64854 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/USS/Wizard.uss +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/USS/Wizard.uss @@ -142,3 +142,20 @@ { margin-top: 3px; } + +.NonBuiltinMaterialWarning +{ + margin-left: 20px; +} + +.InstallConfigPackageMessage +{ + margin-left: 20px; +} + +HelpBox +{ + margin-top: 4px; + margin-bottom: 4px; + margin-right: 12px; +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 07f2a024..a350074b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -1400,37 +1400,6 @@ namespace UnityEngine.Rendering.HighDefinition lighting.children.Add(exposureFoldout); } - var hdrFoldout = new DebugUI.Foldout - { - nameAndTooltip = LightingStrings.HDROutput, - children = - { - new DebugUI.MessageBox - { - displayName = "No HDR monitor detected.", - style = DebugUI.MessageBox.Style.Warning, - isHiddenCallback = () => HDRenderPipeline.HDROutputForMainDisplayIsActive() - }, - new DebugUI.MessageBox - { - displayName = "To display the Gamut View, Gamut Clip, Paper White modes without affecting them, the overlay will be hidden.", - style = DebugUI.MessageBox.Style.Info, - isHiddenCallback = () => !HDRenderPipeline.HDROutputForMainDisplayIsActive() - }, - new DebugUI.EnumField - { - nameAndTooltip = LightingStrings.HDROutputDebugMode, - getter = () => (int)data.lightingDebugSettings.hdrDebugMode, - setter = value => SetHDRDebugMode((HDRDebugMode)value), - autoEnum = typeof(HDRDebugMode), - getIndex = () => data.hdrDebugModeEnumIndex, - setIndex = value => data.hdrDebugModeEnumIndex = value - }, - } - }; - - lighting.children.Add(hdrFoldout); - lighting.children.Add(new DebugUI.EnumField { nameAndTooltip = LightingStrings.LightingDebugMode, getter = () => (int)data.lightingDebugSettings.debugLightingMode, setter = value => SetDebugLightingMode((DebugLightingMode)value), autoEnum = typeof(DebugLightingMode), getIndex = () => data.lightingDebugModeEnumIndex, setIndex = value => { data.ResetExclusiveEnumIndices(); data.lightingDebugModeEnumIndex = value; } }); lighting.children.Add(new DebugUI.Container() @@ -1722,6 +1691,7 @@ namespace UnityEngine.Rendering.HighDefinition static class RenderingStrings { + public static readonly NameAndTooltip RenderingSettings = new() { name = "Rendering Debug", tooltip = "General rendering debug settings" }; public static readonly NameAndTooltip FullscreenDebugMode = new() { name = "Fullscreen Debug Mode", tooltip = "Use the drop-down to select a rendering mode to display as an overlay on the screen." }; public static readonly NameAndTooltip MaxOverdrawCount = new() { name = "Max Overdraw Count", tooltip = "Maximum overdraw count allowed for a single pixel." }; public static readonly NameAndTooltip MaxQuadCost = new() { name = "Max Quad Cost", tooltip = "The scale of the quad mode overdraw heat map." }; @@ -1776,12 +1746,23 @@ namespace UnityEngine.Rendering.HighDefinition widgetList.Add(new DebugUI.RuntimeDebugShadersMessageBox()); - widgetList.Add( + string url = DocumentationInfo.GetPackageLink(Documentation.packageName, Documentation.version, "rendering-debugger-window-reference", "rendering-panel"); + var renderingSettings = new DebugUI.Foldout + { + nameAndTooltip = RenderingStrings.RenderingSettings, + opened = true, // By default this general section is opened + order = int.MinValue, + documentationUrl = url, + }; + + widgetList.Add(renderingSettings); + + renderingSettings.children.Add( new DebugUI.EnumField { nameAndTooltip = RenderingStrings.FullscreenDebugMode, getter = () => (int)data.fullScreenDebugMode, setter = value => SetFullScreenDebugMode((FullScreenDebugMode)value), enumNames = s_RenderingFullScreenDebugStrings, enumValues = s_RenderingFullScreenDebugValues, getIndex = () => data.renderingFulscreenDebugModeEnumIndex, setIndex = value => { data.ResetExclusiveEnumIndices(); data.renderingFulscreenDebugModeEnumIndex = value; } } ); { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => data.fullScreenDebugMode != FullScreenDebugMode.TransparencyOverdraw, children = @@ -1792,7 +1773,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => data.fullScreenDebugMode != FullScreenDebugMode.QuadOverdraw, children = @@ -1803,7 +1784,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => data.fullScreenDebugMode != FullScreenDebugMode.VertexDensity, children = @@ -1814,7 +1795,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => data.fullScreenDebugMode != FullScreenDebugMode.ComputeThickness, children = @@ -1827,7 +1808,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => (data.fullScreenDebugMode != FullScreenDebugMode.MotionVectors || data.fullScreenDebugMode != FullScreenDebugMode.MotionVectorsIntensity), children = @@ -1835,7 +1816,7 @@ namespace UnityEngine.Rendering.HighDefinition new DebugUI.FloatField {displayName = "Min Motion Vector Length (in pixels)", getter = () => data.minMotionVectorLength, setter = value => data.minMotionVectorLength = value, min = () => 0} } }); - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => (data.fullScreenDebugMode != FullScreenDebugMode.MotionVectorsIntensity), children = @@ -1848,7 +1829,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => (data.fullScreenDebugMode != FullScreenDebugMode.HighQualityLines), children = @@ -1859,7 +1840,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => (data.fullScreenDebugMode != FullScreenDebugMode.STP), children = @@ -1870,7 +1851,7 @@ namespace UnityEngine.Rendering.HighDefinition } { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { displayName = "Mipmap Streaming", children = @@ -1965,8 +1946,7 @@ namespace UnityEngine.Rendering.HighDefinition }); } - widgetList.AddRange(new[] - { + renderingSettings.children.Add( new DebugUI.Container { displayName = "Color Picker", @@ -1976,12 +1956,11 @@ namespace UnityEngine.Rendering.HighDefinition new DebugUI.EnumField { nameAndTooltip = RenderingStrings.ColorPickerDebugMode, getter = () => (int)data.colorPickerDebugSettings.colorPickerMode, setter = value => data.colorPickerDebugSettings.colorPickerMode = (ColorPickerDebugMode)value, autoEnum = typeof(ColorPickerDebugMode), getIndex = () => data.colorPickerDebugModeEnumIndex, setIndex = value => data.colorPickerDebugModeEnumIndex = value }, new DebugUI.ColorField { nameAndTooltip = RenderingStrings.ColorPickerFontColor, flags = DebugUI.Flags.EditorOnly, getter = () => data.colorPickerDebugSettings.fontColor, setter = value => data.colorPickerDebugSettings.fontColor = value } } - } - }); + }); - widgetList.Add(new DebugUI.BoolField { nameAndTooltip = RenderingStrings.FalseColorMode, getter = () => data.falseColorDebugSettings.falseColor, setter = value => data.falseColorDebugSettings.falseColor = value}); + renderingSettings.children.Add(new DebugUI.BoolField { nameAndTooltip = RenderingStrings.FalseColorMode, getter = () => data.falseColorDebugSettings.falseColor, setter = value => data.falseColorDebugSettings.falseColor = value}); { - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { isHiddenCallback = () => !data.falseColorDebugSettings.falseColor, flags = DebugUI.Flags.EditorOnly, @@ -1995,12 +1974,9 @@ namespace UnityEngine.Rendering.HighDefinition }); } - widgetList.AddRange(new DebugUI.Widget[] - { - new DebugUI.EnumField { nameAndTooltip = RenderingStrings.FreezeCameraForCulling, getter = () => data.debugCameraToFreeze, setter = value => data.debugCameraToFreeze = value, enumNames = s_CameraNamesStrings, enumValues = s_CameraNamesValues, getIndex = () => data.debugCameraToFreezeEnumIndex, setIndex = value => data.debugCameraToFreezeEnumIndex = value }, - }); + renderingSettings.children.Add(new DebugUI.EnumField { nameAndTooltip = RenderingStrings.FreezeCameraForCulling, getter = () => data.debugCameraToFreeze, setter = value => data.debugCameraToFreeze = value, enumNames = s_CameraNamesStrings, enumValues = s_CameraNamesValues, getIndex = () => data.debugCameraToFreezeEnumIndex, setIndex = value => data.debugCameraToFreezeEnumIndex = value }); - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { displayName = "Color Monitors", children = @@ -2062,21 +2038,7 @@ namespace UnityEngine.Rendering.HighDefinition } }); - widgetList.Add(new DebugUI.Container - { - displayName = "HDR Output", - children = - { - new DebugUI.MessageBox - { - displayName = "The values on the Rendering Debugger editor window might not be accurate. Please use the playmode debug UI (Ctrl+Backspace).", - style = DebugUI.MessageBox.Style.Warning, - }, - DebugDisplaySettingsHDROutput.CreateHDROuputDisplayTable() - } - }); - - widgetList.Add(new DebugUI.Container + renderingSettings.children.Add(new DebugUI.Container { displayName = "History Buffers", children = @@ -2108,12 +2070,51 @@ namespace UnityEngine.Rendering.HighDefinition } }); + var hdrFoldout = new DebugUI.Foldout + { + nameAndTooltip = LightingStrings.HDROutput, + opened = true, + order = int.MinValue + 1, + children = + { + new DebugUI.MessageBox + { + displayName = "No HDR monitor detected.", + style = DebugUI.MessageBox.Style.Warning, + isHiddenCallback = () => HDRenderPipeline.HDROutputForMainDisplayIsActive() + }, + new DebugUI.MessageBox + { + displayName = "The values on the Rendering Debugger editor window might not be accurate. Please use the playmode debug UI (Ctrl+Backspace).", + style = DebugUI.MessageBox.Style.Warning, + }, + new DebugUI.MessageBox + { + displayName = "To display the Gamut View, Gamut Clip, Paper White modes without affecting them, the overlay will be hidden.", + style = DebugUI.MessageBox.Style.Info, + isHiddenCallback = () => !HDRenderPipeline.HDROutputForMainDisplayIsActive() + }, + new DebugUI.EnumField + { + nameAndTooltip = LightingStrings.HDROutputDebugMode, + getter = () => (int)data.lightingDebugSettings.hdrDebugMode, + setter = value => SetHDRDebugMode((HDRDebugMode)value), + autoEnum = typeof(HDRDebugMode), + getIndex = () => data.hdrDebugModeEnumIndex, + setIndex = value => data.hdrDebugModeEnumIndex = value + }, + DebugDisplaySettingsHDROutput.CreateHDROuputDisplayTable() + } + }; + + widgetList.Add(hdrFoldout); + #if ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE widgetList.Add(nvidiaDebugView.CreateWidget()); #endif m_DebugRenderingItems = widgetList.ToArray(); - var panel = DebugManager.instance.GetPanel(k_PanelRendering, true); + var panel = DebugManager.instance.GetPanel(k_PanelRendering,true); panel.children.Add(m_DebugRenderingItems); } @@ -2208,39 +2209,6 @@ namespace UnityEngine.Rendering.HighDefinition } } - internal static void RegisterCamera(IFrameSettingsHistoryContainer container) - { - string name = container.panelName; - if (s_CameraNames.FindIndex(x => x.text.Equals(name)) < 0) - { - s_CameraNames.Add(new GUIContent(name)); - needsRefreshingCameraFreezeList = true; - } - - if (!FrameSettingsHistory.IsRegistered(container)) - { - var history = FrameSettingsHistory.RegisterDebug(container); - DebugManager.instance.RegisterData(history); - } - } - - internal static void UnRegisterCamera(IFrameSettingsHistoryContainer container) - { - string name = container.panelName; - int indexOfCamera = s_CameraNames.FindIndex(x => x.text.Equals(name)); - if (indexOfCamera > 0) - { - s_CameraNames.RemoveAt(indexOfCamera); - needsRefreshingCameraFreezeList = true; - } - - if (FrameSettingsHistory.IsRegistered(container)) - { - DebugManager.instance.UnregisterData(container); - FrameSettingsHistory.UnRegisterDebug(container); - } - } - internal bool IsDebugDisplayRemovePostprocess() { return data.materialDebugSettings.IsDebugDisplayEnabled() || data.lightingDebugSettings.IsDebugDisplayRemovePostprocess() || data.mipMapDebugSettings.IsDebugDisplayEnabled(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs new file mode 100644 index 00000000..46509f72 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Rendering.HighDefinition; +using static UnityEngine.Rendering.DebugUI; + +namespace UnityEngine.Rendering +{ + class DebugDisplaySettingsCamera : IDebugDisplaySettingsData + { + [Serializable] + public class FrameSettingsDebugData + { + private Camera m_SelectedCamera; + public Camera selectedCamera + { + get + { +#if UNITY_EDITOR + if (m_SelectedCamera == null && UnityEditor.SceneView.lastActiveSceneView != null) + { + var sceneCamera = UnityEditor.SceneView.lastActiveSceneView.camera; + if (sceneCamera != null) + m_SelectedCamera = sceneCamera; + } +#endif + return m_SelectedCamera; + } + set + { + if (value != null && value != m_SelectedCamera) + { + m_SelectedCamera = value; + } + } + } + public Dictionary registeredCameras = new (); + } + + public FrameSettingsDebugData frameSettingsData { get; } + + public bool IsCameraRegistered(Camera camera) => frameSettingsData.registeredCameras.ContainsKey(camera); + + public bool RegisterCamera(Camera camera) + { + if (!frameSettingsData.registeredCameras.TryGetValue(camera, out var data)) + { + if (camera.TryGetComponent(out var hdAdditionalCameraData)) + { + var debugData = FrameSettingsHistory.RegisterDebug(hdAdditionalCameraData); + frameSettingsData.registeredCameras.Add(camera, (hdAdditionalCameraData, debugData)); + DebugManager.instance.RegisterData(debugData); + } + else + { + // All scene view will share the same debug FrameSettings as the HDAdditionalData might not be present + if (camera.cameraType == CameraType.SceneView) + { + var debugData = FrameSettingsHistory.RegisterDebug(null, true); + frameSettingsData.registeredCameras.Add(camera, (null, debugData)); + } + else + { + Debug.LogWarning($"[Rendering Debugger] Unable to register camera {camera.name} due to missing {nameof(HDAdditionalCameraData)} component,"); + return false; + } + } + } + + return true; + } + + void IDebugDisplaySettingsData.Reset() + { + FrameSettingsHistory.Clear(); + frameSettingsData.registeredCameras.Clear(); + } + + public DebugDisplaySettingsCamera() + { + this.frameSettingsData = new (); + } + + const string k_PanelTitle = "Camera"; + + static class Strings + { + public static readonly string camera = "Frame Settings"; + } + + internal static class WidgetFactory + { + public static DebugUI.CameraSelector CreateCameraSelector(SettingsPanel panel, + Action, Object> refresh) + { + return new DebugUI.CameraSelector() + { + displayName = Strings.camera, + getter = () => panel.data.frameSettingsData.selectedCamera, + setter = value => + { + if (value is Camera cam && value != panel.data.frameSettingsData.selectedCamera) + panel.data.frameSettingsData.selectedCamera = cam; + }, + onValueChanged = refresh + }; + } + } + + [DisplayInfo(name = k_PanelTitle, order = 40)] + [HDRPHelpURL("rendering-debugger-window-reference", "CameraPanel")] + internal class SettingsPanel : DebugDisplaySettingsPanel + { + public override void Dispose() + { + // Unregister all the cameras from the history + foreach(var registeredCamera in data.frameSettingsData.registeredCameras) + { + FrameSettingsHistory.UnRegisterDebug(registeredCamera.Value.Item1); + } + + var panel = DebugManager.instance.GetPanel(PanelName); + if (panel != null) + { + panel.children.Clear(); + m_FrameSettingsWidgets.Clear(); + } + + base.Dispose(); + } + + DebugUI.CameraSelector m_CameraSelector; + Dictionary> m_FrameSettingsWidgets = new (); + public SettingsPanel(DebugDisplaySettingsCamera data) + : base(data) + { + m_CameraSelector = WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh()); + AddWidget(m_CameraSelector); + + if (GetOrCreateFrameSettingsWidgets(out var frameSettingsWidgets)) + { + foreach (var c in frameSettingsWidgets) + AddWidget(c); + } + } + + bool GetOrCreateFrameSettingsWidgets(out List widgets) + { + widgets = new List(); + + if (data.frameSettingsData.selectedCamera == null) + return false; + + if (!data.IsCameraRegistered(data.frameSettingsData.selectedCamera)) + { + if (!data.RegisterCamera(data.frameSettingsData.selectedCamera)) + return false; + } + + if (!m_FrameSettingsWidgets.TryGetValue(data.frameSettingsData.selectedCamera, out widgets)) + { + widgets ??= new List(); + var cameraInfo = data.frameSettingsData.registeredCameras[data.frameSettingsData.selectedCamera]; + var panelContent = FrameSettingsHistory.GenerateFrameSettingsPanelContent(cameraInfo.Item1); + foreach (var foldout in panelContent) + { + widgets.Add(foldout); + } + + m_FrameSettingsWidgets[data.frameSettingsData.selectedCamera] = widgets; + } + + return widgets.Count != 0; + } + + void Refresh() + { + var panel = DebugManager.instance.GetPanel(PanelName); + if (panel == null) + return; + + panel.children.Clear(); + AddWidget(m_CameraSelector); + panel.children.Add(m_CameraSelector); + + bool needsRefresh = GetOrCreateFrameSettingsWidgets(out var frameSettingsWidgets); + if (needsRefresh) + { + foreach (var c in frameSettingsWidgets) + { + AddWidget(c); + panel.children.Add(c); + } + + DebugManager.instance.ReDrawOnScreenDebug(); + } + } + } + + #region IDebugDisplaySettingsData + /// + /// Checks whether ANY of the debug settings are currently active. + /// + public bool AreAnySettingsActive => false; // This Panel doesn't need to modify the renderer data, therefore this property returns false + + /// + public IDebugDisplaySettingsPanelDisposable CreatePanel() + { + return new SettingsPanel(this); + } + + #endregion + } +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta new file mode 100644 index 00000000..08034c85 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ae2de05020cd37c4ba97bab787d93fd7 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs index 6c757a8d..613cd430 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs @@ -1,4 +1,6 @@ using System; +using System.Reflection; +using UnityEditor; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; namespace UnityEngine.Rendering.HighDefinition @@ -6,6 +8,7 @@ namespace UnityEngine.Rendering.HighDefinition /// /// Decal-related Rendering Debugger settings. /// + [HDRPHelpURL("understand-decals")] class DebugDisplaySettingsDecal : IDebugDisplaySettingsData { internal DecalsDebugSettings m_Data = new DecalsDebugSettings(); @@ -26,22 +29,29 @@ namespace UnityEngine.Rendering.HighDefinition static class Strings { + public const string decals = "Decals"; public const string containerName = "Atlas Texture For Decals"; public static readonly NameAndTooltip displayAtlas = new() { name = "Display Atlas", tooltip = "Enable the checkbox to debug and display the decal atlas for a Camera in the top left of that Camera's view." }; public static readonly NameAndTooltip mipLevel = new() { name = "Mip Level", tooltip = "Use the slider to select the mip level for the decal atlas." }; } - [DisplayInfo(name = "Decals", order = 5)] - [HDRPHelpURL("understand-decals")] + [DisplayInfo(name = "Rendering", order = 5)] private class SettingsPanel : DebugDisplaySettingsPanel { - public override string PanelName => "Decals"; public SettingsPanel(DebugDisplaySettingsDecal data) { - AddWidget(new DebugUI.RuntimeDebugShadersMessageBox()); - AddWidget(new DebugUI.Container() + var foldout = new DebugUI.Foldout() { - displayName = Strings.containerName, + displayName = Strings.decals, + opened = true, + documentationUrl = typeof(DebugDisplaySettingsDecal).GetCustomAttribute()?.URL + }; + AddWidget(foldout); + + foldout.children.Add(new DebugUI.RuntimeDebugShadersMessageBox()); + foldout.children.Add(new DebugUI.Container() + { + displayName = $"#{Strings.containerName}", children = { new DebugUI.BoolField { nameAndTooltip = Strings.displayAtlas, getter = () => data.displayAtlas, setter = value => data.displayAtlas = value}, diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs index 9965c4dc..68c46d2c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs @@ -22,6 +22,8 @@ namespace UnityEngine.Rendering.HighDefinition /// internal DebugDisplayGPUResidentDrawer gpuResidentDrawerSettings { get; private set; } + internal DebugDisplaySettingsCamera cameraSettings { get; private set; } + #if ENABLE_VIRTUALTEXTURES internal DebugDisplayVirtualTexturing vtSettings { get; private set; } #endif @@ -34,9 +36,10 @@ namespace UnityEngine.Rendering.HighDefinition { base.Reset(); displayStats = Add(new DebugDisplaySettingsStats(new HDDebugDisplayStats())); - volumeSettings = Add(new DebugDisplaySettingsVolume(new HDVolumeDebugSettings())); + volumeSettings = Add(new DebugDisplaySettingsVolume()); decalSettings = Add(new DebugDisplaySettingsDecal()); gpuResidentDrawerSettings = Add(new DebugDisplayGPUResidentDrawer()); + cameraSettings = Add(new DebugDisplaySettingsCamera()); #if ENABLE_VIRTUALTEXTURES vtSettings = Add(new DebugDisplayVirtualTexturing()); #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplayStats.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplayStats.cs index 2ce28f74..43b0de0d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplayStats.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplayStats.cs @@ -105,7 +105,6 @@ namespace UnityEngine.Rendering.HighDefinition var detailedStatsFoldout = new DebugUI.Foldout { displayName = "Detailed Stats", - isHeader = true, opened = false, children = { diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDVolumeDebugSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDVolumeDebugSettings.cs index a0075497..09bb0a36 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDVolumeDebugSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDVolumeDebugSettings.cs @@ -1,3 +1,4 @@ +using System; #if UNITY_EDITOR using UnityEditor; #endif @@ -14,6 +15,7 @@ namespace UnityEngine.Rendering.HighDefinition /// This class provides access to debug settings for the volume stack and layer mask in the High Definition Render Pipeline (HDRP). /// It is useful for visualizing and adjusting volume settings for specific cameras during development. /// + [Obsolete("This is not longer supported Please use DebugDisplaySettingsVolume. #from(6000.2)", false)] public partial class HDVolumeDebugSettings : VolumeDebugSettings { /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/NVIDIADebugView.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/NVIDIADebugView.cs index 3082ed5e..20c7a447 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/NVIDIADebugView.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/NVIDIADebugView.cs @@ -164,8 +164,8 @@ namespace UnityEngine.NVIDIA m_DlssViewStateTable.children.Add(m_DlssViewStateTableHeader); - m_DebugWidget = new DebugUI.Container() { - displayName = "NVIDIA device debug view", + m_DebugWidget = new DebugUI.Foldout() { + displayName = "NVIDIA Device settings", children = { new DebugUI.Value() @@ -217,19 +217,19 @@ namespace UnityEngine.NVIDIA { new DebugUI.Value() { - getter = () => c.data.validFeature ? "Valid" : "" + getter = () => c.data.validFeature ? "Valid" : "-" }, new DebugUI.Value() { - getter = () => c.data.validFeature ? resToString(c.data.execData.subrectWidth, c.data.execData.subrectHeight) : "" + getter = () => c.data.validFeature ? resToString(c.data.execData.subrectWidth, c.data.execData.subrectHeight) : "-" }, new DebugUI.Value() { - getter = () => c.data.validFeature ? resToString(c.data.initData.outputRTWidth, c.data.initData.outputRTHeight) : "" + getter = () => c.data.validFeature ? resToString(c.data.initData.outputRTWidth, c.data.initData.outputRTHeight) : "-" }, new DebugUI.Value() { - getter = () => c.data.validFeature ? c.data.initData.quality.ToString() : "" + getter = () => c.data.validFeature ? c.data.initData.quality.ToString() : "-" } } }; @@ -237,7 +237,16 @@ namespace UnityEngine.NVIDIA m_DlssViewStateTableRows[r] = dlssStateRow; } m_DlssViewStateTable.children.Add(m_DlssViewStateTableRows); + m_DlssViewStateTable.isHiddenCallback = () => + { + foreach (var row in m_DlssViewStateTableRows) + { + if (!row.isHidden) + return false; + } + return true; + }; return m_DebugWidget; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs index cd104b6d..03e2f321 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs @@ -9,6 +9,11 @@ namespace UnityEngine.Rendering.HighDefinition : base(pageName, Documentation.packageName) { } + + public HDRPHelpURLAttribute(string pageName, string pageHash) + : base(pageName, pageHash, Documentation.packageName) + { + } } internal class Documentation : DocumentationInfo diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs index 9b1e4493..973f22e6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIllumination.cs @@ -40,7 +40,7 @@ namespace UnityEngine.Rendering.HighDefinition /// /// Controls the fallback hierarchy for indirect diffuse in case the ray misses. /// - [Tooltip("Rendering Layer Mask to use when sampling the Adaptive Probe Volumes.\nThis is only used if Rendering Layers Masks are enabled for the active Baking Set.")] + [Tooltip("Controls which APV rendering layer mask to sample from. If no probes in proximity are from the specified layer or the feature is disabled for the Baking Set, any surrounding probes will be sampled.")] [AdditionalProperty] public RenderingLayerMaskParameter adaptiveProbeVolumesLayerMask = new RenderingLayerMaskParameter(UnityEngine.RenderingLayerMask.defaultRenderingLayerMask); #endregion diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs index 1c8481e8..84a0e190 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs @@ -3726,6 +3726,7 @@ namespace UnityEngine.Rendering.HighDefinition lightRenderData.spotIESCutoffPercent = m_SpotIESCutoffPercent; lightRenderData.shapeRadius = m_ShapeRadius; lightRenderData.barnDoorLength = m_BarnDoorLength; + lightRenderData.barnDoorAngle = m_BarnDoorAngle; lightRenderData.affectVolumetric = useVolumetric; lightRenderData.affectDiffuse = m_AffectDiffuse; lightRenderData.affectSpecular = m_AffectSpecular; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/Deferred.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/Deferred.compute index 6e9de4b2..ea7dac2a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/Deferred.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/Deferred.compute @@ -98,7 +98,7 @@ CBUFFER_END // variable declaration //------------------------------------------------------------------------------------- -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); RW_TEXTURE2D_X(float3, diffuseLightingUAV); RW_TEXTURE2D_X(float4, specularLightingUAV); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl index ec6c2780..e6c21541 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl @@ -31,7 +31,7 @@ GLOBAL_TEXTURE2D(_CookieAtlas, RAY_TRACING_COOKIE_ATLAS_REGISTER); GLOBAL_TEXTURE2D_ARRAY(_ReflectionAtlas, RAY_TRACING_REFLECTION_ATLAS_REGISTER); // Contact shadows -TEXTURE2D_X_UINT(_ContactShadowTexture); +TYPED_TEXTURE2D_X(uint, _ContactShadowTexture); // Screen space shadows TEXTURE2D_ARRAY(_ScreenSpaceShadowsTexture); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/lightlistbuild.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/lightlistbuild.compute index c11ba80e..de711201 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/lightlistbuild.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/lightlistbuild.compute @@ -556,9 +556,14 @@ void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float vL else break; + // Imlicit division by 32, to pick the correct array index. + // E.g 37th light devided by 32 = 1.15 (rounded to 1), so we pick uLightsFlags[1] (which represents the lights from 32 to 64). uLightsFlags[l >> 5] |= lightValid << (l&31); } + // Merge results from all threads into shared memory. + // `InterlockedOr` performs a bitwise OR between `ldsDoesLightIntersect` and `uLightsFlags`. + // This allows multiple threads to update `ldsDoesLightIntersect` without collision. { [unroll(LIGHT_FPTL_VISIBILITY_DWORD_COUNTS)] for (uint ii = 0; ii < LIGHT_FPTL_VISIBILITY_DWORD_COUNTS; ++ii) @@ -570,30 +575,58 @@ void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float vL #endif { - uint localCount = 0; - [unroll(LIGHT_FPTL_VISIBILITY_DWORD_COUNTS)] - for (uint ii = 0; ii < LIGHT_FPTL_VISIBILITY_DWORD_COUNTS; ++ii) - localCount += countbits(ldsDoesLightIntersect[ii]); - - if (t == 0) ldsNrLightsFinal = localCount; + // Reset the total number of lights for the tile. + if (t == 0) + ldsNrLightsFinal = 0; + // Split the job into multiple passes to ensure all lights are processed even if NR_THREADS is smaller than SHADEROPTIONS_FPTLMAX_LIGHT_COUNT. + // A thread will possibly processes many lights. #define MAX_LIGHT_WRITE_LOOP_CNT (((SHADEROPTIONS_FPTLMAX_LIGHT_COUNT+1) + NR_THREADS - 1)/NR_THREADS) [unroll(MAX_LIGHT_WRITE_LOOP_CNT)] for (uint it = 0; it < MAX_LIGHT_WRITE_LOOP_CNT; ++it) { - uint i = t + it * NR_THREADS; - uint lightsMask = ldsDoesLightIntersect[i >> 5]; - uint localMask = (1u << (i & 31)); - if(i<(uint) iNrCoarseLights && (localMask & lightsMask) != 0u) + // Retrieve the light index for the current thread and current iteration. + uint lightIndex = t + it * NR_THREADS; + + // Check if the mask of the current light is valid (intersection with the tile). + uint lightsMask = ldsDoesLightIntersect[lightIndex >> 5]; + + // Select only the current light bit i in the block of 32. + uint localMask = (1u << (lightIndex & 31)); + + // If the thread index is in the light list and the mask is valid. + if (lightIndex < (uint)iNrCoarseLights && (localMask & lightsMask) != 0u) { + // ldsDoesLightIntersect[k] contains the valid lights for each block of 32 lights. + // We sum the number of enabled bits (countbits()) in all blocks before the block i. + // backOffset represents the number of valid lights before the block where i is located. uint backOffset = 0; [unroll(LIGHT_FPTL_VISIBILITY_DWORD_COUNTS)] for (uint k = 0u; k < LIGHT_FPTL_VISIBILITY_DWORD_COUNTS; ++k) - if (k < (i >> 5)) + if (k < (lightIndex >> 5)) backOffset += countbits(ldsDoesLightIntersect[k]); - uint uIndex = backOffset + countbits((localMask - 1u) & lightsMask); - if(uIndex g_TileFeatureFlags; -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); [numthreads(NR_THREADS, 1, 1)] void MaterialFlagsGen(uint3 dispatchThreadId : SV_DispatchThreadID, uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs index 4fbe0934..7e158041 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/HDProbe.cs @@ -791,7 +791,9 @@ namespace UnityEngine.Rendering.HighDefinition internal void TryUpdateLuminanceSHL2ForNormalization() { #if UNITY_EDITOR - m_HasValidSHForNormalization = AdditionalGIBakeRequestsManager.instance.RetrieveProbeSH(GetInstanceID(), out m_SHForNormalization, out m_SHValidForCapturePosition); + const float kValidSHThresh = 0.33f; // This threshold is used to make the code below functionally equivalent to the obsolete RetrieveProbeSH. + m_HasValidSHForNormalization = AdditionalGIBakeRequestsManager.instance.RetrieveProbe(GetEntityId(), out m_SHValidForCapturePosition, out m_SHForNormalization, out float validity); + m_HasValidSHForNormalization = m_HasValidSHForNormalization && validity < kValidSHThresh; if (m_HasValidSHForNormalization) m_SHValidForSourcePosition = transform.position; #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceGlobalIllumination.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceGlobalIllumination.compute index 63619f25..f18dd8ea 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceGlobalIllumination.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceGlobalIllumination.compute @@ -41,7 +41,7 @@ // Input depth pyramid texture TEXTURE2D_X(_DepthTexture); // Stencil buffer of the current frame -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Input texture that holds the offset for every level of the depth pyramid StructuredBuffer _DepthPyramidMipLevelOffsets; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs index ab3e7f9a..70ba09b4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflection.cs @@ -365,6 +365,13 @@ namespace UnityEngine.Rendering.HighDefinition [SerializeField, FormerlySerializedAs("rayMaxIterations")] private MinIntParameter m_RayMaxIterationsRT = new MinIntParameter(48, 0); + + /// + /// Controls which rendering layer mask to prioritize when sampling probes for indirect diffuse in reflections. + /// + [Tooltip("Controls which APV rendering layer mask to sample from. If no probes in proximity are from the specified layer or the feature is disabled for the Baking Set, any surrounding probes will be sampled.")] + [AdditionalProperty] + public RenderingLayerMaskParameter adaptiveProbeVolumesLayerMask = new RenderingLayerMaskParameter(UnityEngine.RenderingLayerMask.defaultRenderingLayerMask); #endregion internal static bool RayTracingActive(ScreenSpaceReflection volume) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute index fa55b512..5aa08154 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceReflections.compute @@ -93,7 +93,7 @@ TEXTURE2D_X(_DepthTexture); #endif #ifdef SSR_TRACE - TEXTURE2D_X_UINT2( _StencilTexture); + TYPED_TEXTURE2D_X(uint2, _StencilTexture); RW_TEXTURE2D_X(float2, _SsrHitPointTexture); #elif defined(SSR_REPROJECT) TEXTURE2D_X( _SsrHitPointTexture); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs index 45c53bb1..a9144bea 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs @@ -84,7 +84,7 @@ namespace UnityEngine.Rendering.HighDefinition public uint _VolumeCount; public uint _IsObliqueProjectionMatrix; - public uint _Padding1; + public float _HalfVoxelArcLength; public uint _Padding2; } @@ -905,7 +905,9 @@ namespace UnityEngine.Rendering.HighDefinition { if (m_VisibleLocalVolumetricFogVolumes.Count >= maxLocalVolumetricFogOnScreen) { - Debug.LogError($"The number of local volumetric fog in the view is above the limit: {m_VisibleLocalVolumetricFogVolumes.Count} instead of {maxLocalVolumetricFogOnScreen}. To fix this, please increase the maximum number of local volumetric fog in the view in the HDRP asset."); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + Debug.LogError($"The number of local volumetric fog in the view is above the limit: {m_VisibleLocalVolumetricFogVolumes.Count + 1} instead of {maxLocalVolumetricFogOnScreen}. To fix this, please increase the maximum number of local volumetric fog in the view in the HDRP asset."); +#endif break; } @@ -990,6 +992,9 @@ namespace UnityEngine.Rendering.HighDefinition cb._MaxSliceCount = (uint)maxSliceCount; cb._MaxVolumetricFogDistance = fog.depthExtent.value; cb._VolumeCount = (uint)m_VisibleLocalVolumetricFogVolumes.Count; + // Compute the arc length of a single froxel at 1m from the camera. + // This value can be used to quickly compute the arc length of a single froxel + cb._HalfVoxelArcLength = Mathf.Deg2Rad * hdCamera.camera.fieldOfView / currParams.viewportSize.y / 2.0f; if (updateVoxelizationFields) { diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl index b86b1cb8..ba3132f9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl @@ -61,7 +61,7 @@ CBUFFER_START(ShaderVariablesVolumetric) float4x4 _CameraInverseViewProjection_NO; uint _VolumeCount; uint _IsObliqueProjectionMatrix; - uint _Padding1; + float _HalfVoxelArcLength; uint _Padding2; CBUFFER_END diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute index 39c7edc9..6507bf51 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute @@ -351,10 +351,15 @@ VoxelLighting EvaluateVoxelLightingLocal(LightLoopContext context, uint groupIdx // Is it worth evaluating the light? if (sampleLight) { - float lightSqRadius = light.size.x; + // Each froxel in the VBuffer is curved following a spherical shape around the camera position + // To compute the arc length of the froxel, we can take the arc length of a forxel at 1m from the camera and multiply it by + // the distance to the current froxel. + float voxelArcLength = _HalfVoxelArcLength * tEntr; + // Modify the light radius to ensure that it's at least the size of the froxel, reducing the aliasing close to the center of the light. + light.size.x = max(light.size.x, voxelArcLength); float t, distSq, rcpPdf; - ImportanceSamplePunctualLight(rndVal, light.positionRWS, lightSqRadius, + ImportanceSamplePunctualLight(rndVal, light.positionRWS, light.size.x, ray.originWS, ray.jitterDirWS, tEntr, tExit, t, distSq, rcpPdf); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader index ded9cab9..4406553f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/AxF/AxF.shader @@ -512,7 +512,7 @@ Shader "HDRP/AxF" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLit.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLit.shader index 0a3e4dd0..1195e8f0 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLit.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLit.shader @@ -680,7 +680,7 @@ Shader "HDRP/LayeredLit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS @@ -1064,7 +1064,7 @@ Shader "HDRP/LayeredLit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitTessellation.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitTessellation.shader index 18e59d72..2517df4c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitTessellation.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitTessellation.shader @@ -721,7 +721,7 @@ Shader "HDRP/LayeredLitTessellation" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS @@ -1117,7 +1117,7 @@ Shader "HDRP/LayeredLitTessellation" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader index 23099cf5..77386cd7 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader @@ -459,7 +459,7 @@ Shader "HDRP/Lit" #pragma multi_compile _ DEBUG_DISPLAY // 'Optimize Mesh Data' strip away attribute uv1/uv2 without the keyword set on the vertex stage. #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING // Both DIRLIGHTMAP_COMBINED and DYNAMICLIGHTMAP_ON must have vertex frequency to be able to include UV2 in player // If DIRLIGHTMAP_COMBINED isn't define, then DYNAMICLIGHTMAP_ON will not. This is hardcoded in C++ // For ShaderGraph we don't have this issue as UV2 are always included. @@ -861,7 +861,7 @@ Shader "HDRP/Lit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS @@ -989,7 +989,7 @@ Shader "HDRP/Lit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl index b0ad1332..93f7935e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl @@ -11,6 +11,7 @@ void ApplyDecalToSurfaceDataNoNormal(DecalSurfaceData decalSurfaceData, inout Su { float3 decalSpecularColor = ComputeFresnel0((decalSurfaceData.baseColor.w < 1.0) ? decalSurfaceData.baseColor.xyz : float3(1.0, 1.0, 1.0), decalSurfaceData.mask.x, DEFAULT_SPECULAR_VALUE); surfaceData.specularColor = surfaceData.specularColor * decalSurfaceData.MAOSBlend.x + decalSpecularColor * (1.0f - decalSurfaceData.MAOSBlend.x); + surfaceData.baseColor = ComputeDiffuseColor(surfaceData.baseColor, decalSurfaceData.mask.x); } #else surfaceData.metallic = surfaceData.metallic * decalSurfaceData.MAOSBlend.x + decalSurfaceData.mask.x; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitTessellation.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitTessellation.shader index e08af888..64bb9e09 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitTessellation.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitTessellation.shader @@ -480,7 +480,7 @@ Shader "HDRP/LitTessellation" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS @@ -889,7 +889,7 @@ Shader "HDRP/LitTessellation" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS @@ -1017,7 +1017,7 @@ Shader "HDRP/LitTessellation" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExtension.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExtension.cs index c032de14..8e79cfb7 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExtension.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExtension.cs @@ -616,7 +616,7 @@ namespace UnityEngine.Rendering.HighDefinition if (shader.FindPropertyIndex("_DiffusionProfileAsset3") != -1) yield return Shader.PropertyToID("_DiffusionProfileAsset3"); - int propertyCount = UnityEditor.ShaderUtil.GetPropertyCount(shader); + int propertyCount = shader.GetPropertyCount(); for (int propIdx = 0; propIdx < propertyCount; ++propIdx) { var attributes = shader.GetPropertyAttributes(propIdx); @@ -625,8 +625,8 @@ namespace UnityEngine.Rendering.HighDefinition if (attribute == "DiffusionProfile") { propIdx++; - var type = UnityEditor.ShaderUtil.GetPropertyType(shader, propIdx); - if (type == UnityEditor.ShaderUtil.ShaderPropertyType.Vector) + var type = shader.GetPropertyType(propIdx); + if (type == ShaderPropertyType.Vector) yield return shader.GetPropertyNameId(propIdx); break; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExternalReferences.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExternalReferences.cs index 8d595b4f..9435ddb2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExternalReferences.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialExternalReferences.cs @@ -51,6 +51,9 @@ namespace UnityEditor.Rendering.HighDefinition MaterialExternalReferences matExternalRefs = null; foreach (var subAsset in subAssets) { + if (subAsset == null) + continue; + if (subAsset.GetType() == typeof(MaterialExternalReferences)) { matExternalRefs = subAsset as MaterialExternalReferences; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs index 93eb858c..e8783a92 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs @@ -33,7 +33,9 @@ namespace UnityEditor.VFX.HDRP [SurfaceDataAttributes(new string[] { "Normal", "Normal World Space" }, true, checkIsNormalized = true)] public Vector3 normalWS; [SurfaceDataAttributes(new string[] { "Tangent", "Tangent World Space" })] - public Vector4 tangentWS; + public Vector3 tangentWS; + [SurfaceDataAttributes(new string[] { "Bitangent", "Bitangent World Space" })] + public Vector3 bitangentWS; [MaterialSharedPropertyMapping(MaterialSharedProperty.AmbientOcclusion)] [SurfaceDataAttributes("Ambient Occlusion", precision = FieldPrecision.Real)] @@ -72,7 +74,9 @@ namespace UnityEditor.VFX.HDRP [SurfaceDataAttributes(new string[] { "Normal WS", "Normal View Space" }, true, checkIsNormalized: true)] public Vector3 normalWS; [SurfaceDataAttributes(new string[] { "Tangent", "Tangent World Space" })] - public Vector4 tangentWS; + public Vector3 tangentWS; + [SurfaceDataAttributes(new string[] { "Bitangent", "Bitangent World Space" })] + public Vector3 bitangentWS; //Smoke Lighting [SurfaceDataAttributes("Rig Right Top Back", precision = FieldPrecision.Real)] diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs.hlsl index 76acb9ce..efb3594e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.cs.hlsl @@ -19,11 +19,13 @@ #define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_NORMAL_VIEW_SPACE (1754) #define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_TANGENT (1755) #define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_TANGENT_WORLD_SPACE (1756) -#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_RIG_RIGHT_TOP_BACK (1757) -#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_RIG_LEFT_BOTTOM_FRONT (1758) -#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING0 (1759) -#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING1 (1760) -#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING2 (1761) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BITANGENT (1757) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BITANGENT_WORLD_SPACE (1758) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_RIG_RIGHT_TOP_BACK (1759) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_RIG_LEFT_BOTTOM_FRONT (1760) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING0 (1761) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING1 (1762) +#define DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BAKE_DIFFUSE_LIGHTING2 (1763) // // UnityEditor.VFX.HDRP.SixWaySmokeLit+SurfaceData: static fields @@ -34,12 +36,14 @@ #define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_NORMAL_WORLD_SPACE (1703) #define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_TANGENT (1704) #define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_TANGENT_WORLD_SPACE (1705) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_AMBIENT_OCCLUSION (1706) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_RIG_RIGHT_TOP_BACK (1707) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_RIG_LEFT_BOTTOM_FRONT (1708) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING0 (1709) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING1 (1710) -#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING2 (1711) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BITANGENT (1706) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BITANGENT_WORLD_SPACE (1707) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_AMBIENT_OCCLUSION (1708) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_RIG_RIGHT_TOP_BACK (1709) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_RIG_LEFT_BOTTOM_FRONT (1710) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING0 (1711) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING1 (1712) +#define DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BAKE_DIFFUSE_LIGHTING2 (1713) // Generated from UnityEditor.VFX.HDRP.SixWaySmokeLit+BSDFData // PackingRules = Exact @@ -50,6 +54,7 @@ struct BSDFData real ambientOcclusion; float3 normalWS; float4 tangentWS; + float3 bitangentWS; real3 rightTopBack; real3 leftBottomFront; real4 bakeDiffuseLighting0; @@ -65,6 +70,7 @@ struct SurfaceData real4 baseColor; float3 normalWS; float4 tangentWS; + float3 bitangentWS; real ambientOcclusion; real3 rightTopBack; real3 leftBottomFront; @@ -102,6 +108,12 @@ void GetGeneratedBSDFDataDebug(uint paramId, BSDFData bsdfdata, inout float3 res case DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_TANGENT_WORLD_SPACE: result = bsdfdata.tangentWS.xyz; break; + case DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BITANGENT: + result = bsdfdata.bitangentWS; + break; + case DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_BITANGENT_WORLD_SPACE: + result = bsdfdata.bitangentWS; + break; case DEBUGVIEW_SIXWAYSMOKELIT_BSDFDATA_RIG_RIGHT_TOP_BACK: result = bsdfdata.rightTopBack; break; @@ -146,6 +158,12 @@ void GetGeneratedSurfaceDataDebug(uint paramId, SurfaceData surfacedata, inout f case DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_TANGENT_WORLD_SPACE: result = surfacedata.tangentWS.xyz; break; + case DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BITANGENT: + result = surfacedata.bitangentWS; + break; + case DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_BITANGENT_WORLD_SPACE: + result = surfacedata.bitangentWS; + break; case DEBUGVIEW_SIXWAYSMOKELIT_SURFACEDATA_AMBIENT_OCCLUSION: result = surfacedata.ambientOcclusion.xxx; break; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl index 5bdff260..e9df3b71 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl @@ -79,6 +79,7 @@ BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData) bsdfData.normalWS = surfaceData.normalWS; bsdfData.tangentWS = surfaceData.tangentWS; + bsdfData.bitangentWS = surfaceData.bitangentWS; bsdfData.diffuseColor = surfaceData.baseColor; bsdfData.absorptionRange = surfaceData.absorptionRange; @@ -152,7 +153,7 @@ void SixWayBakedDiffuseLighting(BSDFData bsdfData, inout BuiltinData builtinData bool alphaPremultipled = (_BlendMode == BLENDINGMODE_PREMULTIPLY); const real3 L0 = real3(bsdfData.bakeDiffuseLighting0.w, bsdfData.bakeDiffuseLighting1.w, bsdfData.bakeDiffuseLighting2.w); - const real3 diffuseGIData[3] = { bsdfData.bakeDiffuseLighting0.xyz, bsdfData.bakeDiffuseLighting1.xyz, bsdfData.tangentWS.w * bsdfData.bakeDiffuseLighting2.xyz}; + const real3 diffuseGIData[3] = { bsdfData.bakeDiffuseLighting0.xyz, bsdfData.bakeDiffuseLighting1.xyz, bsdfData.bakeDiffuseLighting2.xyz}; builtinData.bakeDiffuseLighting = GetSixWayDiffuseContributions(bsdfData.rightTopBack, bsdfData.leftBottomFront, @@ -166,17 +167,15 @@ float3x3 GetLocalTBN(float3 normal, float4 tangent) { float3 zVec = -normal; float3 xVec = tangent.xyz; - float3 yVec = cross(zVec, xVec) * tangent.w; + float3 yVec = cross(normal, tangent.xyz) * tangent.w ; return float3x3(xVec, yVec, zVec); } - float3 TransformToLocalFrame(float3 L, BSDFData bsdfData) { - float3x3 tbn = GetLocalTBN(bsdfData.normalWS, bsdfData.tangentWS); + float3x3 tbn = float3x3(bsdfData.tangentWS.xyz, bsdfData.bitangentWS, -bsdfData.normalWS); return mul(tbn, L); } - void GatherLightProbeData(float3 positionRWS, float3x3 tbn, out float4 diffuseGIData[3]) { if (unity_ProbeVolumeParams.x == 0.0) @@ -186,7 +185,7 @@ void GatherLightProbeData(float3 positionRWS, float3x3 tbn, out float4 diffuseGI [unroll] for (int i = 0; i<3; i++) { - float3 bakeDiffuseLighting = EvaluateLightProbeL1(tbn[i]); + float3 bakeDiffuseLighting = EvaluateLightProbeL1(tbn[i] * kInvClampedCosine1); diffuseGIData[i].xyz = bakeDiffuseLighting; diffuseGIData[i].w = ambientL0[i]; } @@ -199,7 +198,7 @@ void GatherLightProbeData(float3 positionRWS, float3x3 tbn, out float4 diffuseGI float3 bakeDiffuseLighting = 0; float3 backBakeDiffuseLighting = 0; // Note: Probe volume here refer to LPPV not APV - SampleProbeVolumeSH4(TEXTURE3D_ARGS(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH), positionRWS, tbn[i], -tbn[i], GetProbeVolumeWorldToObject(), + SampleProbeVolumeSH4(TEXTURE3D_ARGS(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH), positionRWS, tbn[i] * kInvClampedCosine1, -tbn[i] * kInvClampedCosine1, GetProbeVolumeWorldToObject(), unity_ProbeVolumeParams.y, unity_ProbeVolumeParams.z, unity_ProbeVolumeMin.xyz, unity_ProbeVolumeSizeInv.xyz, bakeDiffuseLighting, backBakeDiffuseLighting); float3 ambientL0 = 0.5f * (bakeDiffuseLighting + backBakeDiffuseLighting); @@ -217,7 +216,7 @@ void SampleAPVSixWay(APVSample apvSample, float3x3 tbn, out float4 diffuseGIData for (int i = 0; i<3; i++) { float3 bakeDiffuseLighting; - EvaluateAPVL1(apvSample, tbn[i], bakeDiffuseLighting); + EvaluateAPVL1(apvSample, tbn[i] * kInvClampedCosine1 , bakeDiffuseLighting); diffuseGIData[i].xyz = bakeDiffuseLighting; diffuseGIData[i].w = apvSample.L0[i]; } @@ -229,7 +228,7 @@ void EvaluateAmbientProbeSixWay(float weight, float3x3 tbn, out float4 diffuseGI [unroll] for (int i = 0; i<3; i++) { - float3 bakeDiffuseLighting = EvaluateAmbientProbeL1(tbn[i]) * (1.0f - weight); + float3 bakeDiffuseLighting = EvaluateAmbientProbeL1(tbn[i] * kInvClampedCosine1) * (1.0f - weight); diffuseGIData[i].xyz = bakeDiffuseLighting; diffuseGIData[i].w = ambientL0[i]; } @@ -244,9 +243,7 @@ void GatherAPVData(float3 positionRWS, float3x3 tbn, out float4 diffuseGIData[3] if (apvSample.status != APV_SAMPLE_STATUS_INVALID) { - #if MANUAL_FILTERING == 0 apvSample.Decode(); - #endif SampleAPVSixWay(apvSample, tbn, diffuseGIData); //Sample Only L1 even if L2 is available diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit.shader index dafe0c53..b774c332 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit.shader @@ -133,7 +133,7 @@ Shader "HDRP/TerrainLit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK @@ -289,7 +289,7 @@ Shader "HDRP/TerrainLit" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit_Basemap.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit_Basemap.shader index 3f54cecb..95b1f988 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit_Basemap.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/TerrainLit/TerrainLit_Basemap.shader @@ -89,7 +89,7 @@ Shader "Hidden/HDRP/TerrainLit_Basemap" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK @@ -228,7 +228,7 @@ Shader "Hidden/HDRP/TerrainLit_Basemap" #pragma multi_compile _ DEBUG_DISPLAY #pragma multi_compile _ LIGHTMAP_ON - #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader index 8dee2fc4..557bc105 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/CompositeWithUIAndOETF.shader @@ -21,13 +21,16 @@ Shader "Hidden/HDRP/CompositeUI" CBUFFER_START(cb) float4 _HDROutputParams; + float4 _SrcOffset; int _NeedsFlip; int _BlitTexArraySlice; CBUFFER_END - #define _MinNits _HDROutputParams.x - #define _MaxNits _HDROutputParams.y - #define _PaperWhite _HDROutputParams.z + #define _MinNits _HDROutputParams.x + #define _MaxNits _HDROutputParams.y + #define _PaperWhite _HDROutputParams.z + #define _FullScreenHeight _SrcOffset.w + #define _ViewportLoadOffset _SrcOffset.xy struct Attributes { @@ -58,11 +61,14 @@ Shader "Hidden/HDRP/CompositeUI" float2 uv = input.texcoord; float2 samplePos = input.positionCS.xy; + float2 pixelSampleOffset = float2(-_ViewportLoadOffset.x, _ViewportLoadOffset.y); if (_NeedsFlip) { uv.y = _RTHandleScale.y - uv.y; samplePos.y = _ScreenSize.y - samplePos.y; + pixelSampleOffset.y = (_FullScreenHeight - _ScreenSize.y) - pixelSampleOffset.y; } + samplePos += pixelSampleOffset; #if defined(USE_TEXTURE2D_X_AS_ARRAY) && defined(BLIT_SINGLE_SLICE) float4 outColor = LOAD_TEXTURE2D_ARRAY(_InputTexture, samplePos.xy, _BlitTexArraySlice); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurMergeTilePass.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurMergeTilePass.compute index 71fe92bf..703c3c86 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurMergeTilePass.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurMergeTilePass.compute @@ -3,7 +3,7 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurTileCommon.hlsl" -TEXTURE2D_X_UINT(_TileToScatterMax); +TYPED_TEXTURE2D_X(uint, _TileToScatterMax); TEXTURE2D_X(_TileToScatterMin); RW_TEXTURE2D_X(float3, _TileMaxNeighbourhood); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntiAliasing.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntiAliasing.shader index 15a2ecd6..b973fbf5 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntiAliasing.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntiAliasing.shader @@ -123,7 +123,7 @@ Shader "Hidden/HDRP/TemporalAA" #endif #if DIRECT_STENCIL_SAMPLE - TEXTURE2D_X_UINT2(_StencilTexture); + TYPED_TEXTURE2D_X(uint2, _StencilTexture); #endif float4 _TaaPostParameters; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs index 1e03a638..3272cba7 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs @@ -524,9 +524,6 @@ namespace UnityEngine.Rendering.HighDefinition set => m_RenderingPathHistory = value; } - string IFrameSettingsHistoryContainer.panelName - => m_CameraRegisterName; - /// /// . /// @@ -634,14 +631,6 @@ namespace UnityEngine.Rendering.HighDefinition public IEnumerable aovRequests => m_AOVRequestDataCollection ?? (m_AOVRequestDataCollection = new AOVRequestDataCollection(null)); - // Use for debug windows - // When camera name change we need to update the name in DebugWindows. - // This is the purpose of this class - [ExcludeCopy] - bool m_IsDebugRegistered = false; - [ExcludeCopy] - string m_CameraRegisterName; - // When we are a preview, there is no way inside Unity to make a distinction between camera preview and material preview. // This property allow to say that we are an editor camera preview when the type is preview. /// @@ -741,37 +730,6 @@ namespace UnityEngine.Rendering.HighDefinition return nonObliqueProjectionGetter(camera); } - void RegisterDebug() - { - if (!m_IsDebugRegistered) - { - // Note that we register FrameSettingsHistory, so manipulating FrameSettings in the Debug windows - // doesn't affect the serialized version - // Note camera's preview camera is registered with preview type but then change to game type that lead to issue. - // Do not attempt to not register them till this issue persist. - m_CameraRegisterName = name; - if (m_Camera.cameraType != CameraType.Preview && m_Camera.cameraType != CameraType.Reflection) - { - DebugDisplaySettings.RegisterCamera(this); - } - m_IsDebugRegistered = true; - } - } - - void UnRegisterDebug() - { - if (m_IsDebugRegistered) - { - // Note camera's preview camera is registered with preview type but then change to game type that lead to issue. - // Do not attempt to not register them till this issue persist. - if (m_Camera.cameraType != CameraType.Preview && m_Camera?.cameraType != CameraType.Reflection) - { - DebugDisplaySettings.UnRegisterCamera(this); - } - m_IsDebugRegistered = false; - } - } - void OnEnable() { if(GraphicsSettings.currentRenderPipelineAssetType != typeof(HDRenderPipelineAsset)) @@ -793,34 +751,6 @@ namespace UnityEngine.Rendering.HighDefinition FrameSettings dummy = new FrameSettings(); //don't require full init as will be fully reset in AggregateFrameSettings if (GraphicsSettings.TryGetRenderPipelineSettings(out var renderingPathFrameSettings)) FrameSettingsHistory.AggregateFrameSettings(renderingPathFrameSettings, ref dummy, m_Camera, this, HDRenderPipeline.currentAsset, null); - - RegisterDebug(); - -#if UNITY_EDITOR - UpdateDebugCameraName(); - UnityEditor.EditorApplication.hierarchyChanged += UpdateDebugCameraName; -#endif - } - - void UpdateDebugCameraName() - { - // Move the garbage generated by accessing name outside of HDRP - profilingSampler = new ProfilingSampler(HDUtils.ComputeCameraName(name)); - - if (name != m_CameraRegisterName) - { - UnRegisterDebug(); - RegisterDebug(); - } - } - - void OnDisable() - { - UnRegisterDebug(); - -#if UNITY_EDITOR - UnityEditor.EditorApplication.hierarchyChanged -= UpdateDebugCameraName; -#endif } // This is called at the creation of the HD Additional Camera Data, to convert the legacy camera settings to HD diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs index 60c75990..b82b59a6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs @@ -1872,6 +1872,14 @@ namespace UnityEngine.Rendering.HighDefinition internal bool vrsEnabled => frameSettings.IsEnabled(FrameSettingsField.VariableRateShading) && camera.cameraType == CameraType.Game && !xr.enabled; + + + internal bool allowRayTracingCullingOverride { get; private set; } = true; + + internal void SetRayTracingCullingOverride(bool allow) + { + allowRayTracingCullingOverride = allow; + } #endregion 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 57d787ca..f7885a7e 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 @@ -48,12 +48,13 @@ namespace UnityEngine.Rendering.HighDefinition /// /// Debug display settings. /// - public DebugDisplaySettings debugDisplaySettings { get { return m_DebugDisplaySettings; } } - static DebugDisplaySettings s_NeutralDebugDisplaySettings = new DebugDisplaySettings(); + public DebugDisplaySettings debugDisplaySettings => m_DebugDisplaySettings; + private static DebugDisplaySettings s_NeutralDebugDisplaySettings; internal DebugDisplaySettings m_CurrentDebugDisplaySettings; void InitializeDebug() { + s_NeutralDebugDisplaySettings ??= new DebugDisplaySettings(); m_ComputePositionNormal = runtimeShaders.probeVolumeSamplingDebugComputeShader; m_DebugViewMaterialGBuffer = CoreUtils.CreateEngineMaterial(runtimeShaders.debugViewMaterialGBufferPS); m_DebugViewMaterialGBufferShadowMask = CoreUtils.CreateEngineMaterial(runtimeShaders.debugViewMaterialGBufferPS); 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 0f0eb310..8449d35f 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 @@ -212,6 +212,8 @@ namespace UnityEngine.Rendering.HighDefinition RenderForwardOpaque(m_RenderGraph, hdCamera, colorBuffer, lightingBuffers, gpuLightListOutput, prepassOutput, vtFeedbackBuffer, shadowResult, cullingResults); + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.AfterOpaqueColor, aovRequest, aovCustomPassBuffers, lightingBuffers); + if (IsComputeThicknessNeeded(hdCamera)) // Compute the thickness for All Transparent which can be occluded by opaque written on the DepthBuffer (which includes the Forward Opaques). RenderThickness(m_RenderGraph, cullingResults, thicknessTexture, prepassOutput.depthPyramidTexture, hdCamera, HDRenderQueue.k_RenderQueue_AllTransparent, true); @@ -226,7 +228,7 @@ namespace UnityEngine.Rendering.HighDefinition // Send all the geometry graphics buffer to client systems if required (must be done after the pyramid and before the transparent depth pre-pass) SendGeometryGraphicsBuffers(m_RenderGraph, prepassOutput.normalBuffer, prepassOutput.depthPyramidTexture, hdCamera); - RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.AfterOpaqueAndSky, aovRequest, aovCustomPassBuffers); + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.AfterOpaqueAndSky, aovRequest, aovCustomPassBuffers, lightingBuffers); DoUserAfterOpaqueAndSky(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedDepthBuffer, prepassOutput.resolvedNormalBuffer, prepassOutput.resolvedMotionVectorsBuffer); @@ -335,7 +337,7 @@ namespace UnityEngine.Rendering.HighDefinition // At this point, the color buffer has been filled by either debug views are regular rendering so we can push it here. var colorPickerTexture = PushColorPickerDebugTexture(m_RenderGraph, colorBuffer); - RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovCustomPassBuffers); + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovCustomPassBuffers, lightingBuffers); if (aovRequest.isValid) { @@ -537,6 +539,7 @@ namespace UnityEngine.Rendering.HighDefinition if (data.hdrOutputParmeters.x >= 0) { data.blitMaterial.SetInt(HDShaderIDs._NeedsFlip, data.flip ? 1 : 0); + propertyBlock.SetVector(HDShaderIDs._SrcOffset, new Vector4(data.viewport.x, data.viewport.y, Screen.width, Screen.height)); propertyBlock.SetTexture(HDShaderIDs._UITexture, data.uiTexture); propertyBlock.SetTexture(HDShaderIDs._InputTexture, sourceTexture); @@ -1589,7 +1592,7 @@ namespace UnityEngine.Rendering.HighDefinition if (hasWater) { // Render the water gbuffer (and prepare for the transparent SSR pass) - output.waterGBuffer = m_WaterSystem.RenderWaterGBuffer(renderGraph, cullingResults, hdCamera, prepassOutput.depthBuffer, prepassOutput.normalBuffer, currentColorPyramid, prepassOutput.depthPyramidTexture, lightLists); + output.waterGBuffer = m_WaterSystem.RenderWaterGBuffer(renderGraph, cullingResults, hdCamera, prepassOutput.depthBuffer, prepassOutput.normalBuffer, currentColorPyramid, output.depthBufferPreRefraction, lightLists); // Render Water Line m_WaterSystem.RenderWaterLine(renderGraph, hdCamera, prepassOutput.depthBuffer, ref output); @@ -2260,7 +2263,8 @@ namespace UnityEngine.Rendering.HighDefinition CullingResults cameraCullingResults, CustomPassInjectionPoint injectionPoint, AOVRequestData aovRequest, - List aovCustomPassBuffers) + List aovCustomPassBuffers, + in LightingBuffers lightingBuffers = default) { if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass)) return false; @@ -2283,6 +2287,8 @@ namespace UnityEngine.Rendering.HighDefinition motionVectorBufferRG = prepassOutput.resolvedMotionVectorsBuffer, renderingLayerMaskRG = renderingLayerMaskBuffer, shadingRateImageRG = prepassOutput.shadingRateImage, + sssBuffer = lightingBuffers.sssBuffer, + diffuseLightingBuffer = lightingBuffers.diffuseLightingBuffer, waterLineRG = prepassOutput.waterLine, }; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index e2280115..4e6358be 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -668,19 +668,6 @@ namespace UnityEngine.Rendering.HighDefinition m_DebugDisplaySettingsUI.RegisterDebug(HDDebugDisplaySettings.Instance); #endif -#if UNITY_EDITOR - // We don't need the debug of Scene View at runtime (each camera have its own debug settings) - // All scene view will share the same FrameSettings for now as sometimes Dispose is called after - // another instance of HDRenderPipeline constructor is called. - - Camera firstSceneViewCamera = UnityEditor.SceneView.sceneViews.Count > 0 ? (UnityEditor.SceneView.sceneViews[0] as UnityEditor.SceneView).camera : null; - if (firstSceneViewCamera != null) - { - var history = FrameSettingsHistory.RegisterDebug(null, true); - DebugManager.instance.RegisterData(history); - } -#endif - m_DepthPyramidMipLevelOffsetsBuffer = new ComputeBuffer(15, sizeof(int) * 2); m_CustomPassColorBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GetCustomBufferFormat(), enableRandomWrite: true, useDynamicScale: true, name: "CustomPassColorBuffer")); @@ -1700,6 +1687,13 @@ namespace UnityEngine.Rendering.HighDefinition } } + void HandleCullingFailed(HDCullingResults cullingResults, CubemapFace face, ref ProbeRenderSteps skippedRenderSteps) + { + // Skip request and free resources + m_CullingResultsPool.Release(cullingResults); + skippedRenderSteps |= ProbeRenderStepsExt.FromCubeFace(face); + } + void AddHDProbeRenderRequests( HDProbe visibleProbe, Transform viewerTransform, @@ -1739,6 +1733,7 @@ namespace UnityEngine.Rendering.HighDefinition var probeFormat = (GraphicsFormat)m_Asset.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionProbeFormat; + var isPlanarReflectionProbe = false; switch (visibleProbe.type) { case ProbeSettings.ProbeType.ReflectionProbe: @@ -1753,6 +1748,7 @@ namespace UnityEngine.Rendering.HighDefinition } break; case ProbeSettings.ProbeType.PlanarProbe: + isPlanarReflectionProbe = true; if (visibleProbe.IsTurnedOff()) { @@ -1838,26 +1834,30 @@ namespace UnityEngine.Rendering.HighDefinition var _cullingResults = m_CullingResultsPool.Get(); _cullingResults.Reset(); - if (!(TryCalculateFrameParameters( - camera, - XRSystem.emptyPass, - out _, - out var hdCamera, - out var cullingParameters - ) - && TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, XRSystem.emptyPass, ref _cullingResults) - )) + if (!TryCalculateFrameParameters(camera, XRSystem.emptyPass, out _, out var hdCamera, out var cullingParameters)) { - // Skip request and free resources - m_CullingResultsPool.Release(_cullingResults); - skippedRenderSteps |= ProbeRenderStepsExt.FromCubeFace(face); + HandleCullingFailed(_cullingResults, face, ref skippedRenderSteps); + continue; + } + + if (isPlanarReflectionProbe) + { + hdCamera.SetRayTracingCullingOverride(false); + } + + var cullSuccess = TryCull(camera, hdCamera, renderContext, m_SkyManager, cullingParameters, m_Asset, XRSystem.emptyPass, ref _cullingResults); + hdCamera.SetRayTracingCullingOverride(true); + + if(!cullSuccess) + { + HandleCullingFailed(_cullingResults, face, ref skippedRenderSteps); continue; } bool useFetchedGpuExposure = false; float fetchedGpuExposure = 1.0f; - if (visibleProbe.type == ProbeSettings.ProbeType.PlanarProbe) + if (isPlanarReflectionProbe) { //cache the resolved settings. Otherwise if we use the internal probe settings, it will be the wrong resolved result. visibleProbe.ExposureControlEnabled = hdCamera.exposureControlFS; @@ -3128,7 +3128,8 @@ namespace UnityEngine.Rendering.HighDefinition skyManager.UpdateCurrentSkySettings(hdCamera); skyManager.SetupAmbientProbe(hdCamera); - if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing)) + if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && + hdCamera.allowRayTracingCullingOverride) { OverrideCullingForRayTracing(hdCamera, camera, ref cullingParams); } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.Migration.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.Migration.cs index 973b4c20..1a1124ae 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.Migration.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.Migration.cs @@ -174,8 +174,9 @@ namespace UnityEngine.Rendering.HighDefinition MigrationStep.New(Version.RenderingLayerMask, (HDRenderPipelineGlobalSettings data) => { #pragma warning disable 618 // Type or member is obsolete - if (data.renderingLayerNames == null) + if (data.renderingLayerNames == null || data.renderingLayerNames.Length == 0) return; + for (int i = 1; i < data.renderingLayerNames.Length; i++) { if (i >= UnityEngine.RenderingLayerMask.GetRenderingLayerCount()) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.HDRTASManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.HDRTASManager.cs index eabd55f7..9df69a3d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.HDRTASManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.HDRTASManager.cs @@ -276,7 +276,7 @@ namespace UnityEngine.Rendering.HighDefinition } // We want the LODs to match the rasterization and we want to exclude reflection probes - cullingConfig.flags |= RayTracingInstanceCullingFlags.EnableLODCulling | RayTracingInstanceCullingFlags.IgnoreReflectionProbes; + cullingConfig.flags |= RayTracingInstanceCullingFlags.EnableLODCulling | RayTracingInstanceCullingFlags.IgnoreReflectionProbes | RayTracingInstanceCullingFlags.EnableMeshLOD; // Dirtiness need to be kept track of for the path tracing (when enabled) if (pathTracingEnabled) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs index 3fc8f1c1..819a2a26 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs @@ -746,7 +746,9 @@ namespace UnityEngine.Rendering.HighDefinition if (!m_ValidRayTracingState) return; - using (var builder = renderGraph.AddRenderPass("Debug view of the RTAS", out var passData, ProfilingSampler.Get(HDProfileId.RaytracingBuildAccelerationStructureDebug))) + RTASDebugPassData passData; + + using (var builder = renderGraph.AddRenderPass("Debug view of the RTAS", out passData, ProfilingSampler.Get(HDProfileId.RaytracingBuildAccelerationStructureDebug))) { builder.EnableAsyncCompute(false); @@ -788,10 +790,10 @@ namespace UnityEngine.Rendering.HighDefinition // Evaluate the debug view ctx.cmd.DispatchRays(data.debugRTASRT, m_RTASDebugRTKernel, (uint)data.actualWidth, (uint)data.actualHeight, (uint)data.viewCount); }); - - // Use the debug texture to do the full screen debug - PushFullScreenDebugTexture(renderGraph, passData.outputTexture, FullScreenDebugMode.RayTracingAccelerationStructure); } + + // Use the debug texture to do the full screen debug + PushFullScreenDebugTexture(renderGraph, passData.outputTexture, FullScreenDebugMode.RayTracingAccelerationStructure); } internal static int RayTracingFrameIndex(HDCamera hdCamera, int targetFrameCount = 8) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingRecursiveRenderer.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingRecursiveRenderer.cs index 02397124..b377d13a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingRecursiveRenderer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingRecursiveRenderer.cs @@ -102,7 +102,9 @@ namespace UnityEngine.Rendering.HighDefinition if (!validEffect) return colorBuffer; - using (var builder = renderGraph.AddRenderPass("Recursive Rendering Evaluation", out var passData, ProfilingSampler.Get(HDProfileId.RayTracingRecursiveRendering))) + RecursiveRenderingPassData passData; + + using (var builder = renderGraph.AddRenderPass("Recursive Rendering Evaluation", out passData, ProfilingSampler.Get(HDProfileId.RayTracingRecursiveRendering))) { builder.EnableAsyncCompute(false); @@ -188,11 +190,11 @@ namespace UnityEngine.Rendering.HighDefinition // Run the computation ctx.cmd.DispatchRays(data.recursiveRenderingRT, m_RayGenShaderName, (uint)data.texWidth, (uint)data.texHeight, (uint)data.viewCount); }); + } - PushFullScreenDebugTexture(m_RenderGraph, passData.debugBuffer, FullScreenDebugMode.RecursiveRayTracing); + PushFullScreenDebugTexture(m_RenderGraph, passData.debugBuffer, FullScreenDebugMode.RecursiveRayTracing); - return passData.outputBuffer; - } + return passData.outputBuffer; } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs index 4bddb9b2..78cc3e87 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs @@ -440,6 +440,7 @@ namespace UnityEngine.Rendering.HighDefinition deferredParameters.raytracingCB._RayTracingRayMissUseAmbientProbeAsSky = 0; deferredParameters.raytracingCB._RayTracingLastBounceFallbackHierarchy = deferredParameters.lastBounceFallbackHierarchy; deferredParameters.raytracingCB._RayTracingAmbientProbeDimmer = settings.ambientProbeDimmer.value; + deferredParameters.raytracingCB._RaytracingAPVLayerMask = settings.adaptiveProbeVolumesLayerMask.value; return deferredParameters; } @@ -500,6 +501,7 @@ namespace UnityEngine.Rendering.HighDefinition public int rayMissfallbackHierarchy; public int lastBouncefallbackHierarchy; public float ambientProbeDimmer; + public UnityEngine.RenderingLayerMask adaptiveProbeVolumesLayerMask; public int frameIndex; // Other parameters @@ -553,6 +555,7 @@ namespace UnityEngine.Rendering.HighDefinition passData.rayMissfallbackHierarchy = (int)settings.rayMiss.value; passData.lastBouncefallbackHierarchy = (int)settings.lastBounceFallbackHierarchy.value; passData.ambientProbeDimmer = settings.ambientProbeDimmer.value; + passData.adaptiveProbeVolumesLayerMask = settings.adaptiveProbeVolumesLayerMask.value; passData.frameIndex = RayTracingFrameIndex(hdCamera, 32); // Other parameters @@ -607,6 +610,7 @@ namespace UnityEngine.Rendering.HighDefinition data.shaderVariablesRayTracingCB._RayTracingLastBounceFallbackHierarchy = data.lastBouncefallbackHierarchy; data.shaderVariablesRayTracingCB._RayTracingAmbientProbeDimmer = data.ambientProbeDimmer; data.shaderVariablesRayTracingCB._RayTracingReflectionFrameIndex = data.frameIndex; + data.shaderVariablesRayTracingCB._RaytracingAPVLayerMask = data.adaptiveProbeVolumesLayerMask.value; ConstantBuffer.PushGlobal(ctx.cmd, data.shaderVariablesRayTracingCB, HDShaderIDs._ShaderVariablesRaytracing); // Inject the ray-tracing sampling data diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl index 73671d3a..c539209e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl @@ -6,7 +6,7 @@ // Depth buffer of the current frame TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); TEXTURE2D_X(_ClearCoatMaskTexture); // ---------------------------------------------------------------------------- diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_BilateralUtilities.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_BilateralUtilities.hlsl index 9f37788c..1225ef4e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_BilateralUtilities.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_BilateralUtilities.hlsl @@ -2,7 +2,7 @@ #define REBLUR_BILATERAL_UTILITIES_H_ TEXTURE2D_X(_LightingDistanceHistoryBuffer); -TEXTURE2D_X_UINT(_AccumulationHistoryBuffer); +TYPED_TEXTURE2D_X(uint, _AccumulationHistoryBuffer); TEXTURE2D_X(_HistoryDepthTexture); // Function that holds everything relative to the bilateral tap region diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute index efa63300..526bda3d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute @@ -26,7 +26,7 @@ // Input texture TEXTURE2D_X(_LightingDistanceTexture); -TEXTURE2D_X_UINT(_AccumulationTexture); +TYPED_TEXTURE2D_X(uint, _AccumulationTexture); // Output texture RW_TEXTURE2D_X(float4, _LightingDistanceTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_CopyHistory.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_CopyHistory.compute index 5ec53679..f419f570 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_CopyHistory.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_CopyHistory.compute @@ -13,7 +13,7 @@ // Input textures TEXTURE2D_X(_LightingDistanceTexture); #if defined(ACCUMULATION) -TEXTURE2D_X_UINT(_AccumulationTexture); +TYPED_TEXTURE2D_X(uint, _AccumulationTexture); #endif // Output texture diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute index d622ad8a..e9f21be4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute @@ -15,7 +15,7 @@ // Input texture TEXTURE2D_X(_LightingDistanceTexture); -TEXTURE2D_X_UINT(_AccumulationTexture); +TYPED_TEXTURE2D_X(uint, _AccumulationTexture); TEXTURE2D_X(_DepthTexture); StructuredBuffer _DepthPyramidMipLevelOffsets; TEXTURE2D_X(_ReBlurMipChain); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PostBlur.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PostBlur.compute index 1f9d8b9c..cbed1a07 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PostBlur.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PostBlur.compute @@ -23,7 +23,7 @@ // Input buffers TEXTURE2D_X(_LightingDistanceTexture); -TEXTURE2D_X_UINT(_AccumulationTexture); +TYPED_TEXTURE2D_X(uint, _AccumulationTexture); // Output texture RW_TEXTURE2D_X(float4, _LightingDistanceTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute index fb0f675d..0b7554bb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute @@ -18,7 +18,7 @@ // Depth and history depth TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT(_ValidationBuffer); +TYPED_TEXTURE2D_X(uint, _ValidationBuffer); TEXTURE2D_X(_ClearCoatMaskTexture); // Input texture diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute index bbc29ab6..319721ab 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute @@ -32,8 +32,8 @@ TEXTURE2D_X(_DenoiseInputTexture); TEXTURE2D_X(_StabilizationHistoryBuffer); TEXTURE2D_X(_HistoryBuffer); TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT(_ValidationBuffer); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint, _ValidationBuffer); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output texture RW_TEXTURE2D_X(float4, _DenoiseOutputTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/TemporalFilter.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/TemporalFilter.compute index d062e3a9..f0a6dc75 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/TemporalFilter.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/TemporalFilter.compute @@ -38,7 +38,7 @@ // Depth buffer of the current frame TEXTURE2D_X(_DepthTexture); // Stencil buffer of the current frame -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); int _ObjectMotionStencilBit; // Depth buffer of the previous frame TEXTURE2D_X(_HistoryDepthTexture); @@ -147,7 +147,7 @@ void ValidateHistory(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupTh } // Validation buffer that tells us if the history should be ignored for a given pixel. -TEXTURE2D_X_UINT(_ValidationBuffer); +TYPED_TEXTURE2D_X(uint, _ValidationBuffer); #ifdef HISTORY_IS_ARRAY // This buffer holds the previously accumualted signal TEXTURE2D_ARRAY(_HistoryBuffer); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RayTracingIndirectDiffuse.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RayTracingIndirectDiffuse.hlsl index 86a4b5f6..abeec698 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RayTracingIndirectDiffuse.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RayTracingIndirectDiffuse.hlsl @@ -44,7 +44,7 @@ // The target acceleration structure that we will evaluate the reflexion in TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output structure of the reflection raytrace shader RW_TEXTURE2D_X(float4, _IndirectDiffuseTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RaytracingIndirectDiffuse.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RaytracingIndirectDiffuse.compute index bdd0d815..4acd845c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RaytracingIndirectDiffuse.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/IndirectDiffuse/RaytracingIndirectDiffuse.compute @@ -29,7 +29,7 @@ #define RAYTRACING_INDIRECT_DIFFUSE_TILE_SIZE 8 TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); RW_TEXTURE2D_X(float4, _RaytracingDirectionBuffer); [numthreads(RAYTRACING_INDIRECT_DIFFUSE_TILE_SIZE, RAYTRACING_INDIRECT_DIFFUSE_TILE_SIZE, 1)] diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayMarching.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayMarching.compute index f873e172..7e04b366 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayMarching.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayMarching.compute @@ -32,7 +32,7 @@ TEXTURE2D_X(_InputDepthTexture); // Input depth pyramid texture TEXTURE2D_X(_DepthTexture); // Stencil texture -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Input direction buffer RW_TEXTURE2D_X(float4, _RaytracingDirectionBuffer); // Input texture that holds the offset for every level of the depth pyramid diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingSubSurface.raytrace b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingSubSurface.raytrace index 7159aa39..c1e71a96 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingSubSurface.raytrace +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingSubSurface.raytrace @@ -24,7 +24,7 @@ // Input texture TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output texture RW_TEXTURE2D_X(float4, _ThroughputTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingAmbientOcclusion.raytrace b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingAmbientOcclusion.raytrace index e24bc6e2..d5ab088c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingAmbientOcclusion.raytrace +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingAmbientOcclusion.raytrace @@ -20,7 +20,7 @@ // The target acceleration structure that we will evaluate the reflexion in TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output structure of the reflection raytrace shader RW_TEXTURE2D_X(float, _AmbientOcclusionTextureRW); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute index f9930d22..a426d991 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute @@ -29,7 +29,7 @@ TEXTURE2D_X(_DepthTexture); TEXTURE2D_X(_SsrLightingTextureRW); TEXTURE2D_X(_DirectionPDFTexture); TEXTURE2D_X(_SsrClearCoatMaskTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output Textures for the spatial filtering RW_TEXTURE2D_X(float4, _RaytracingReflectionTexture); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.compute index 5d326fbc..12aa9dd3 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.compute @@ -30,7 +30,7 @@ // Input data TEXTURE2D_X(_DepthTexture); -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Flag value that defines if a given pixel recieves reflections or not int _SsrStencilBit; TEXTURE2D_X(_SsrClearCoatMaskTexture); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.raytrace b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.raytrace index d7e59f8b..80f2270f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.raytrace +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Reflections/RaytracingReflections.raytrace @@ -44,7 +44,7 @@ TEXTURE2D_X(_DepthTexture); TEXTURE2D_X(_SsrClearCoatMaskTexture); // Flag value that defines if a given pixel recieves reflections or not -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); int _SsrStencilBit; // Output structure of the reflection raytrace shader diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.compute index bcac8513..def31ddb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.compute @@ -58,7 +58,7 @@ TEXTURE2D_X(_DepthTexture); // Flag value that defines if a given pixel is deferred or not -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); // Output buffers of the shadows raytrace shader RW_TEXTURE2D_X(float2, _AnalyticProbBuffer); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs index 52081bb8..03fa1be1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs @@ -170,6 +170,8 @@ namespace UnityEngine.Rendering.HighDefinition public TextureHandle motionVectorBufferRG; public TextureHandle renderingLayerMaskRG; public TextureHandle shadingRateImageRG; + public TextureHandle sssBuffer; + public TextureHandle diffuseLightingBuffer; public BufferHandle waterLineRG; } @@ -236,6 +238,10 @@ namespace UnityEngine.Rendering.HighDefinition output.waterLineRG = builder.ReadBuffer(targets.waterLineRG); if (targets.shadingRateImageRG.IsValid() && hdCamera.vrsEnabled) output.shadingRateImageRG = builder.ReadTexture(targets.shadingRateImageRG); + if (targets.sssBuffer.IsValid()) + output.sssBuffer = builder.ReadWriteTexture(targets.sssBuffer); + if (targets.diffuseLightingBuffer.IsValid()) + output.diffuseLightingBuffer = builder.ReadWriteTexture(targets.diffuseLightingBuffer); return output; } @@ -263,7 +269,9 @@ namespace UnityEngine.Rendering.HighDefinition ctx.cmd.SetGlobalFloat(HDShaderIDs._CustomPassInjectionPoint, (float)customPass.injectionPoint); if (customPass.currentRenderTarget.colorBufferRG.IsValid() && customPass.injectionPoint == CustomPassInjectionPoint.AfterPostProcess) + { ctx.cmd.SetGlobalTexture(HDShaderIDs._AfterPostProcessColorBuffer, customPass.currentRenderTarget.colorBufferRG); + } if (customPass.currentRenderTarget.motionVectorBufferRG.IsValid() && (customPass.injectionPoint != CustomPassInjectionPoint.BeforeRendering)) ctx.cmd.SetGlobalTexture(HDShaderIDs._CameraMotionVectorsTexture, customPass.currentRenderTarget.motionVectorBufferRG); @@ -312,6 +320,8 @@ namespace UnityEngine.Rendering.HighDefinition customPass.currentRenderTarget.depthBufferRG, customPass.currentRenderTarget.normalBufferRG, customPass.currentRenderTarget.motionVectorBufferRG, + customPass.currentRenderTarget.sssBuffer, + customPass.currentRenderTarget.diffuseLightingBuffer, customPass.currentRenderTarget.customColorBuffer, customPass.currentRenderTarget.customDepthBuffer, ctx.renderGraphPool.GetTempMaterialPropertyBlock(), diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs index 3700ab21..36320b97 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs @@ -72,6 +72,9 @@ namespace UnityEngine.Rendering.HighDefinition /// public readonly RTHandle shadingRateBuffer; + internal readonly RTHandle sssBuffer; + internal readonly RTHandle diffuseLightingBuffer; + internal readonly CustomPassInjectionPoint injectionPoint; // This represent the state of HDRP globals at the point of recording the custom passes. // Using GetShaderVariablesGlobals() from HDRP inside the execute of the custom pass would give invalid result @@ -84,7 +87,7 @@ namespace UnityEngine.Rendering.HighDefinition CullingResults cameraCullingResults, RTHandle cameraColorBuffer, RTHandle cameraDepthBuffer, RTHandle cameraNormalBuffer, RTHandle cameraMotionVectorsBuffer, - Lazy customColorBuffer, + RTHandle sssBuffer, RTHandle diffuseLightingBuffer, Lazy customColorBuffer, Lazy customDepthBuffer, MaterialPropertyBlock propertyBlock, RTHandle shadingRateBuffer, CustomPassInjectionPoint injectionPoint, ShaderVariablesGlobal currentGlobalState) @@ -102,6 +105,8 @@ namespace UnityEngine.Rendering.HighDefinition this.customDepthBuffer = customDepthBuffer; this.propertyBlock = propertyBlock; this.shadingRateBuffer = shadingRateBuffer; + this.sssBuffer = sssBuffer; + this.diffuseLightingBuffer = diffuseLightingBuffer; this.injectionPoint = injectionPoint; this.currentGlobalState = currentGlobalState; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs index e5a63a90..0f032fee 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs @@ -18,6 +18,8 @@ namespace UnityEngine.Rendering.HighDefinition BeforeRendering = 0, /// At this point, you can modify the normal, roughness, and depth buffer. If you write to these buffers at this injection point, HDRP takes it into account in the lighting and the depth pyramid. AfterOpaqueDepthAndNormal = 5, + /// At this injection point, The color buffer contains all the opaque objects in your view. The Sky and the Fog is not rendered yet, so if you change the color buffer in this injection point, fog will be applied on top of your effect. + AfterOpaqueColor = 7, /// At this injection point, The color buffer contains all the opaque objects in your view as well as the sky. The Fog is not rendered yet, so if you change the color buffer in this injection point, fog will be applied on top of your effect. AfterOpaqueAndSky = 6, /// At this injection point, you can render any transparent GameObject that you want to see in refraction. If you write to buffers at this injection point, they contents end up in the color pyramid that HDRP uses for refraction when it draws transparent GameObjects. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs.hlsl index 36efe130..5aeac7b6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassInjectionPoint.cs.hlsl @@ -9,6 +9,7 @@ // #define CUSTOMPASSINJECTIONPOINT_BEFORE_RENDERING (0) #define CUSTOMPASSINJECTIONPOINT_AFTER_OPAQUE_DEPTH_AND_NORMAL (5) +#define CUSTOMPASSINJECTIONPOINT_AFTER_OPAQUE_COLOR (7) #define CUSTOMPASSINJECTIONPOINT_AFTER_OPAQUE_AND_SKY (6) #define CUSTOMPASSINJECTIONPOINT_BEFORE_PRE_REFRACTION (4) #define CUSTOMPASSINJECTIONPOINT_BEFORE_TRANSPARENT (1) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs index c4a949ad..be965306 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs @@ -24,7 +24,6 @@ namespace UnityEngine.Rendering.HighDefinition FrameSettingsOverrideMask frameSettingsMask { get; } FrameSettings frameSettings { get; } bool hasCustomFrameSettings { get; } - string panelName { get; } } struct FrameSettingsHistory @@ -65,9 +64,6 @@ namespace UnityEngine.Rendering.HighDefinition bool IFrameSettingsHistoryContainer.hasCustomFrameSettings => false; - string IFrameSettingsHistoryContainer.panelName - => "Scene Camera"; - public MinimalHistoryContainer() { m_FrameSettingsHistory.debug = GraphicsSettings.TryGetRenderPipelineSettings(out var renderingPathFrameSettings) @@ -81,6 +77,7 @@ namespace UnityEngine.Rendering.HighDefinition // => m_FrameSettingsHistory.TriggerReset => () => m_FrameSettingsHistory.TriggerReset(); } + internal static IFrameSettingsHistoryContainer sceneViewFrameSettingsContainer = new MinimalHistoryContainer(); #endif internal static HashSet containers = new HashSet(); @@ -291,32 +288,23 @@ namespace UnityEngine.Rendering.HighDefinition return area; } - static DebugUI.Widget[] GenerateFrameSettingsPanelContent(IFrameSettingsHistoryContainer frameSettingsContainer) + internal static DebugUI.Widget[] GenerateFrameSettingsPanelContent(IFrameSettingsHistoryContainer frameSettingsContainer) { +#if UNITY_EDITOR + frameSettingsContainer ??= sceneViewFrameSettingsContainer; +#endif + if (frameSettingsContainer == null) + return Array.Empty(); + var panelContent = new DebugUI.Widget[foldoutNames.Length]; for (int index = 0; index < foldoutNames.Length; ++index) { - panelContent[index] = new DebugUI.Foldout(foldoutNames[index], GenerateHistoryArea(frameSettingsContainer, index), columnNames, columnTooltips); + panelContent[index] = new DebugUI.Foldout(foldoutNames[index], + GenerateHistoryArea(frameSettingsContainer, index), columnNames, columnTooltips); } return panelContent; } - static void GenerateFrameSettingsPanel(string menuName, IFrameSettingsHistoryContainer frameSettingsContainer) - { - List widgets = new List(); - widgets.AddRange(GenerateFrameSettingsPanelContent(frameSettingsContainer)); - var panel = DebugManager.instance.GetPanel( - menuName, - createIfNull: true, -#if UNITY_EDITOR - frameSettingsContainer == sceneViewFrameSettingsContainer - ? 100 : // Scene Camera -#endif - 101, // Other Cameras (from Camera component) - overrideIfExist: true); - panel.children.Add(widgets.ToArray()); - } - static Type RetrieveEnumTypeByField(FrameSettingsField field) { switch (field) @@ -334,16 +322,23 @@ namespace UnityEngine.Rendering.HighDefinition frameSettingsContainer = sceneViewFrameSettingsContainer; #endif - GenerateFrameSettingsPanel(frameSettingsContainer.panelName, frameSettingsContainer); containers.Add(frameSettingsContainer); return frameSettingsContainer; } + public static void Clear() + { +#if UNITY_EDITOR + sceneViewFrameSettingsContainer = new MinimalHistoryContainer(); +#endif + containers.Clear(); + } + /// Unregister FrameSettingsHistory for DebugMenu public static void UnRegisterDebug(IFrameSettingsHistoryContainer container) { - DebugManager.instance.RemovePanel(container.panelName); - containers.Remove(container); + if (container != null) + containers.Remove(container); } /// Check if a camera is registered. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ResolveStencilBuffer.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ResolveStencilBuffer.compute index 142c5d03..03ae1f2e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ResolveStencilBuffer.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ResolveStencilBuffer.compute @@ -27,7 +27,7 @@ TEXTURE2D_X_MSAA(uint2, _StencilTexture); RW_TEXTURE2D_X(uint2, _OutputStencilBuffer); #else -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); #endif // TODO: Wasting 3 bytes here per entry, but still better than a texture as can be scalar read. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Tools/ColorCheckerTool.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Tools/ColorCheckerTool.cs index fb9cd9ea..58c3c25b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Tools/ColorCheckerTool.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Tools/ColorCheckerTool.cs @@ -3,13 +3,14 @@ using System.Collections.Generic; using System.Collections; using UnityEngine; using UnityEngine.Rendering; - +using UnityEngine.Rendering.HighDefinition; [ExecuteInEditMode] [SelectionBaseAttribute] /// /// This component generates a procedural color checker. /// +[HDRPHelpURL("color-checker-tool-reference")] public class ColorCheckerTool : MonoBehaviour { /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl index 6a0b8b93..a3ed5921 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl @@ -196,21 +196,29 @@ SurfaceData VFXGetSurfaceData(const VFX_VARYING_PS_INPUTS i, float3 normalWS,con color.a = SampleCurve(i.VFX_VARYING_ALPHA_REMAP, color.a); #endif + float frontFaceSign = frontFace ? 1.0f : -1.0f; + #if defined(VFX_VARYING_BAKE_DIFFUSE_LIGHTING) surfaceData.bakeDiffuseLighting0 = i.VFX_VARYING_BAKE_DIFFUSE_LIGHTING[0]; surfaceData.bakeDiffuseLighting1 = i.VFX_VARYING_BAKE_DIFFUSE_LIGHTING[1]; surfaceData.bakeDiffuseLighting2 = i.VFX_VARYING_BAKE_DIFFUSE_LIGHTING[2]; + surfaceData.bakeDiffuseLighting2.xyz *= frontFaceSign; #endif - #ifdef VFX_VARYING_TANGENT - float signBitangent = frontFace ? 1.0f : -1.0f; - surfaceData.tangentWS = float4(i.VFX_VARYING_TANGENT.xyz,signBitangent); + #if defined(VFX_VARYING_TANGENT) + #if VFX_PRIMITIVE_QUAD || VFX_PRIMITIVE_TRIANGLE || VFX_PRIMITIVE_OCTAGON + float4 tangentWS = float4(i.VFX_VARYING_TANGENT, -1.0f); + #else + float4 tangentWS = i.VFX_VARYING_TANGENT; + #endif #else - surfaceData.tangentWS = float4(1,0,0,1); + float4 tangentWS = float4(1,0,0,1); #endif - surfaceData.baseColor.a = mapAlpha; + surfaceData.tangentWS = tangentWS; + surfaceData.bitangentWS = cross(normalWS, surfaceData.tangentWS.xyz) * frontFaceSign * tangentWS.w * GetOddNegativeScale(); + surfaceData.baseColor.a = mapAlpha; #endif color = VFXApplySoftParticleFade(i, color); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl index b197d5c0..4061c468 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl @@ -18,7 +18,7 @@ // Buffers used for refraction sorting #if defined(SUPPORT_WATER_ABSORPTION) || defined (_TRANSPARENT_REFRACTIVE_SORT) -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); TEXTURE2D_X(_RefractiveDepthBuffer); #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterLine.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterLine.compute index 3c595270..0557f3dd 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterLine.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterLine.compute @@ -11,7 +11,7 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl" -TEXTURE2D_X_UINT2(_StencilTexture); +TYPED_TEXTURE2D_X(uint2, _StencilTexture); TEXTURE2D_X(_DepthTexture); // 1D WaterLine Buffer, contains the vertical (along upVector) height of the water line diff --git a/Packages/com.unity.render-pipelines.high-definition/package.json b/Packages/com.unity.render-pipelines.high-definition/package.json index 67eba72d..16bf5c81 100644 --- a/Packages/com.unity.render-pipelines.high-definition/package.json +++ b/Packages/com.unity.render-pipelines.high-definition/package.json @@ -1,17 +1,17 @@ { "name": "com.unity.render-pipelines.high-definition", "description": "The High Definition Render Pipeline (HDRP) is a high-fidelity Scriptable Render Pipeline built by Unity to target modern (Compute Shader compatible) platforms. HDRP utilizes Physically-Based Lighting techniques, linear lighting, HDR lighting, and a configurable hybrid Tile/Cluster deferred/Forward lighting architecture and gives you the tools you need to create games, technical demos, animations, and more to a high graphical standard.", - "version": "17.1.0", - "unity": "6000.1", + "version": "17.2.0", + "unity": "6000.2", "displayName": "High Definition Render Pipeline", "dependencies": { "com.unity.modules.video": "1.0.0", "com.unity.modules.animation": "1.0.0", "com.unity.modules.imageconversion": "1.0.0", - "com.unity.render-pipelines.core": "17.1.0", - "com.unity.shadergraph": "17.1.0", - "com.unity.visualeffectgraph": "17.1.0", - "com.unity.render-pipelines.high-definition-config": "17.1.0" + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.shadergraph": "17.2.0", + "com.unity.visualeffectgraph": "17.2.0", + "com.unity.render-pipelines.high-definition-config": "17.2.0" }, "keywords": [ "graphics", @@ -100,5 +100,5 @@ ] } ], - "_fingerprint": "3672d1571dfd5f4d1627647460e0e4e2f11422ae" + "_fingerprint": "28765669b6fee79d765751f370129f832b2c30c4" } 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 7113ff55..b98eca50 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 @@ -5,6 +5,8 @@ using System.Runtime.InteropServices; using Unity.Mathematics; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Rendering.RadeonRays; +using UnityEngine; +using UnityEngine.TestTools; namespace UnityEngine.Rendering.UnifiedRayTracing.Tests { @@ -170,7 +172,7 @@ namespace UnityEngine.Rendering.UnifiedRayTracing.Tests } [Test] - [Timeout(360000)] + [Ignore("Test too unstable on Yamato (UUM-95662, UUM-67382)")] 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 6c0b217f..73f71d9d 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": "e647573c7d2ae78386ecb3f9f962738597f13fcf" + "_fingerprint": "2c9279f90d7c8dfb6e76e3f90b6b3be1cafabfbc" } diff --git a/Packages/com.unity.shadergraph/CHANGELOG.md b/Packages/com.unity.shadergraph/CHANGELOG.md index da17ab4a..d69fc158 100644 --- a/Packages/com.unity.shadergraph/CHANGELOG.md +++ b/Packages/com.unity.shadergraph/CHANGELOG.md @@ -12,15 +12,36 @@ The version number for this package has increased due to a version update of a r ## [17.0.3] - 2025-02-13 -This version is compatible with Unity 6000.2.0a1. +This version is compatible with Unity 6000.2.0a5. ### Changed +- Added a new *Shader Graph UGUI Shaders* sample content set to the Shader Graph package. This sample demonstrates how to use the new Canvas target in Shader Graph to create dynamic UI elements. You can import this sample from the *Samples* tab in the Package Manager after selecting the Shader Graph package. - Added support for spacewarp to Shader Graph. - Added a new *Shader Graph UGUI Shaders* sample content set to the Shader Graph package. This sample demonstrates how to use the new Canvas target in Shader Graph to create dynamic UI elements. You can import this sample from the *Samples* tab in the Package Manager after selecting the Shader Graph package. - Removed duplicate LIGHTMAP_ON and DIRLIGHTMAP_COMBINED variants when generating shaders for builtin-deferred. - Added a new set of sample content - Shader Graph UGUI Shaders - to the Shader Graph package that contains examples of how to use the new Canvas target in Shader Graph to create dynamic UI elements. This new sample can be imported from the Sample tab of the Package Manager after selecting the Shader Graph package ### Fixed +- Fixed "Element 'UnityEditor.UIElements.VisualSplitter' is missing a UxmlElementAttribute" error logged in the Console when creating a new Node in ShaderGraph +- Fixed an issue where horizontal scrollbars did not work as expected in the Blackboard or Graph Inspector. +- Fixed an issue where certain warning messages did not display with enough contrast in the Blackboard and Graph Inspector. +- Fixed "Shader error in 'ProBuilder6/Standard Vertex Color': 'PBRDeferredFragment'" error logged in the console when compiling the shader. +- Fixed the generation of new artifact ID of ShaderGraph on every reimport. +- Fixed an issue where the Main Preview could be resized beyond its containing Shader Graph window +- Allowed latin alphabet for variable names. +- Correct sticky note context menu shortcut display text. +- Color properties now default to opaque (alpha = 1). +- Forum link in info replaced with link to unity discussions. +- Exposed aniso setting on blackboard sampler state properties. +- Added SHADERGRAPH_PREVIEW_MAIN define specifically for main previews. +- Addressed issue where HDR Colors would cause errors when used with custom render to texture target. +- Fixed issue where some resources failed to dispose properly when entering play mode in editor. +- Addressed an issue where the property sheet could complain about type mismatch for preview properties. +- Fixed null reference when shadergraph editor is open while entering playmode. +- Custom function node previews are hidden unless the first output is a previewable type (vector or float). +- Fixed issue where graphs with groups in them would sometimes become modified upon opening the shader graph editor. +- Enabled custom interpolators for custom sprite lit target. +- Fixed an issue where the Blackboard would not scroll to show newly-created properties. - Fixed a bug that a shader graph is reverted to its last saved state when entering Play Mode without saving changes. - Added missing documentation about the Custom Render Texture in Shader Graph. - [Metal] Fix shader compilation errors due to Foveated Rendering when building URP 3D template. diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/AbstractShaderProperty.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/AbstractShaderProperty.cs index 2faa21f5..938f2253 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/AbstractShaderProperty.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/AbstractShaderProperty.cs @@ -91,7 +91,33 @@ namespace UnityEditor.ShaderGraph.Internal set => m_Hidden = value; } - internal string hideTagString => hidden || (shouldForceExposed && !isExposed) ? "[HideInInspector]" : ""; + [SerializeField] + bool m_PerRendererData = false; + internal bool PerRendererData + { + get => m_PerRendererData; + set => m_PerRendererData = value; + } + + internal string hideTagString => hidden || (shouldForceExposed && !isExposed) ? $"[HideInInspector]" : perRendererDataTagString; + internal string perRendererDataTagString => PerRendererData ? "[PerRendererData]" : ""; + + [Serializable] + internal class PropertyAttribute + { + public string name; + public string value; + + internal PropertyAttribute(string name, string value) + { + this.name = name; + this.value = value; + } + } + + [SerializeField] + List m_customAttributes = new(); + internal List customAttributes => m_customAttributes; // reference names are the HLSL declaration name / property block ref name internal virtual void GetPropertyReferenceNames(List result) @@ -117,7 +143,18 @@ namespace UnityEditor.ShaderGraph.Internal // the more complex interface for complex properties (defaulted for simple properties) internal virtual void AppendPropertyBlockStrings(ShaderStringBuilder builder) { - builder.AppendLine(GetPropertyBlockString()); + string attributesPrefix = string.Empty; + + foreach (var attribute in customAttributes) + { + if (string.IsNullOrEmpty(attribute.value)) + attributesPrefix += $"[{attribute.name}]"; + else + attributesPrefix += $"[{attribute.name}({attribute.value})]"; + } + + string propertyBlockString = attributesPrefix + GetPropertyBlockString(); + builder.AppendLine(propertyBlockString); } internal abstract void ForeachHLSLProperty(Action action); diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs index 120d2c8d..f8cc1a59 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs @@ -1375,7 +1375,7 @@ namespace UnityEditor.ShaderGraph { if (asset is null || !asset.isValid || asset.isNull) return; - + foreach(var keyword in asset.keywords) { collector.AddShaderKeyword(keyword); diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderKeyword.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderKeyword.cs index 667d28a0..f243b675 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderKeyword.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderKeyword.cs @@ -64,6 +64,8 @@ namespace UnityEditor.ShaderGraph set => m_KeywordType = value; } + internal bool IsDynamic => m_KeywordDefinition == KeywordDefinition.DynamicBranch; + [SerializeField] private KeywordDefinition m_KeywordDefinition = KeywordDefinition.ShaderFeature; @@ -173,7 +175,23 @@ namespace UnityEditor.ShaderGraph public string GetKeywordPreviewDeclarationString() { - switch (keywordType) + if (this.IsDynamic) + { + switch(keywordType) + { + case KeywordType.Boolean: + return $"#define {referenceName} {(value == 0 ? "false" : " true")}"; + case KeywordType.Enum: + string result = $"#define {referenceName}_{entries[value].referenceName} true"; + for (int i = 0; i < entries.Count; ++i) + if (i != value) + result += $"\n#define {referenceName}_{entries[i].referenceName} false"; + return result; + default: + throw new ArgumentOutOfRangeException(); + } + } + else switch (keywordType) { case KeywordType.Boolean: return value == 1 ? $"#define {referenceName}" : string.Empty; diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs index cda01df1..08773683 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs @@ -46,7 +46,7 @@ namespace UnityEditor.ShaderGraph.Internal switch (enumType) { case EnumType.CSharpEnum: - return $"[Enum({m_CSharpEnumType.ToString()})]"; + return $"[Enum({(m_CSharpEnumType != null ? m_CSharpEnumType.ToString() : m_CSharpEnumString)})]"; case EnumType.KeywordEnum: return $"[KeywordEnum({string.Join(", ", enumNames)})]"; default: @@ -61,6 +61,22 @@ namespace UnityEditor.ShaderGraph.Internal } } + string sliderTagString + { + get + { + switch (sliderType) + { + case SliderType.Power: + return $"[PowerSlider({m_SliderPower})]"; + case SliderType.Integer: + return $"[IntRange]"; + default: + return string.Empty; + } + } + } + internal override string GetHLSLVariableName(bool isSubgraphProperty, GenerationMode mode) { HLSLDeclaration decl = GetDefaultHLSLDeclaration(); @@ -77,7 +93,7 @@ namespace UnityEditor.ShaderGraph.Internal switch (floatType) { case FloatType.Slider: - return $"{hideTagString}{referenceName}(\"{displayName}\", Range({NodeUtils.FloatToShaderValueShaderLabSafe(m_RangeValues.x)}, {NodeUtils.FloatToShaderValueShaderLabSafe(m_RangeValues.y)})) = {valueString}"; + return $"{hideTagString}{sliderTagString}{referenceName}(\"{displayName}\", Range({NodeUtils.FloatToShaderValueShaderLabSafe(m_RangeValues.x)}, {NodeUtils.FloatToShaderValueShaderLabSafe(m_RangeValues.y)})) = {valueString}"; case FloatType.Integer: return $"{hideTagString}{referenceName}(\"{displayName}\", Int) = {((int)value).ToString(CultureInfo.InvariantCulture)}"; case FloatType.Enum: @@ -116,6 +132,16 @@ namespace UnityEditor.ShaderGraph.Internal set => m_RangeValues = value; } + [SerializeField] + SliderType m_SliderType = SliderType.Default; + + internal SliderType sliderType { get => m_SliderType; set => m_SliderType = value; } + + [SerializeField] + float m_SliderPower = 3.0f; + internal float sliderPower { get => m_SliderPower; set => m_SliderPower = value; } + + [SerializeField] EnumType m_EnumType = EnumType.Enum; public EnumType enumType @@ -132,7 +158,17 @@ namespace UnityEditor.ShaderGraph.Internal set => m_CSharpEnumType = value; } - List m_EnumNames = new List(); + [SerializeField] + string m_CSharpEnumString; + + internal string cSharpEnumString + { + get => m_CSharpEnumString; + set => m_CSharpEnumString = value; + } + + [SerializeField] + List m_EnumNames = new List() { "Default" }; public List enumNames { @@ -140,7 +176,8 @@ namespace UnityEditor.ShaderGraph.Internal set => m_EnumNames = value; } - List m_EnumValues = new List(); + [SerializeField] + List m_EnumValues = new List() { 0 }; public List enumValues { @@ -199,5 +236,7 @@ namespace UnityEditor.ShaderGraph.Internal public enum FloatType { Default, Slider, Integer, Enum } + internal enum SliderType { Default, Power, Integer } + public enum EnumType { Enum, CSharpEnum, KeywordEnum, } } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/VectorShaderProperty.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/VectorShaderProperty.cs index 5e220c48..fac3a41c 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/VectorShaderProperty.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/VectorShaderProperty.cs @@ -23,7 +23,7 @@ namespace UnityEditor.ShaderGraph.Internal internal override string GetPropertyBlockString() { - return $"{hideTagString}{referenceName}(\"{displayName}\", Vector) = ({NodeUtils.FloatToShaderValueShaderLabSafe(value.x)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.y)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.z)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.w)})"; + return $"{hideTagString}{referenceName}(\"{displayName}\", Vector, {vectorDimension}) = ({NodeUtils.FloatToShaderValueShaderLabSafe(value.x)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.y)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.z)}, {NodeUtils.FloatToShaderValueShaderLabSafe(value.w)})"; } internal override string GetPropertyAsArgumentString(string precisionString) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs b/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs index 13ed5baa..79dabe57 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs @@ -118,7 +118,7 @@ namespace UnityEditor.Graphing // If this node is a keyword node and we have an active keyword permutation // The only valid port id is the port that corresponds to that keywords value in the active permutation - if (node is KeywordNode keywordNode && keywordPermutation != null) + if (node is KeywordNode keywordNode && keywordPermutation != null && !keywordNode.keyword.IsDynamic) { var valueInPermutation = keywordPermutation.Where(x => x.Key == keywordNode.keyword).FirstOrDefault(); ids = new int[] { keywordNode.GetSlotIdForPermutation(valueInPermutation) }; diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs new file mode 100644 index 00000000..369b89cd --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using UnityEditor.Graphing; +using UnityEngine; + +namespace UnityEditor.ShaderGraph +{ + [Title("Channel", "Append")] + class AppendVectorNode : AbstractMaterialNode, IGeneratesBodyCode + { + public AppendVectorNode() + { + name = "Append"; + synonyms = new string[] { "join", "combine" }; + UpdateNodeAfterDeserialization(); + } + + const int Input1SlotId = 0; + const int Input2SlotId = 1; + const int OutputSlotId = 2; + const string kInput1SlotName = "A"; + const string kInput2SlotName = "B"; + const string kOutputSlotName = "Out"; + + public override bool hasPreview => true; + + public sealed override void UpdateNodeAfterDeserialization() + { + AddSlot(new DynamicVectorMaterialSlot(Input1SlotId, kInput1SlotName, kInput1SlotName, SlotType.Input, Vector4.zero)); + AddSlot(new DynamicVectorMaterialSlot(Input2SlotId, kInput2SlotName, kInput2SlotName, SlotType.Input, Vector4.zero)); + AddSlot(new DynamicVectorMaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector4.zero)); + RemoveSlotsNameNotMatching(new[] { Input1SlotId, Input2SlotId, OutputSlotId }); + } + + public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) + { + var input1Value = GetSlotValue(Input1SlotId, generationMode); + var input2Value = GetSlotValue(Input2SlotId, generationMode); + var outputValue = GetSlotValue(OutputSlotId, generationMode); + + var outputTypeString = FindOutputSlot(OutputSlotId).concreteValueType.ToShaderString(); + var input1Type = FindInputSlot(Input1SlotId).concreteValueType; + var input2Type = FindInputSlot(Input2SlotId).concreteValueType; + + var input1Swizzle = SwizzleFromVectorSlotType(input1Type, 3); + var input2Swizzle = SwizzleFromVectorSlotType(input2Type, 3); + + sb.AppendLine("{0} {1} = {0}( {2}.{3}, {4}.{5} );", + outputTypeString, + GetVariableNameForSlot(OutputSlotId), + input1Value, + input1Swizzle, + input2Value, + input2Swizzle + ); + } + + string SwizzleFromVectorSlotType( ConcreteSlotValueType type , uint dimensionLimit = 3) + { + if (dimensionLimit == 0) + dimensionLimit = 4; + + uint typeDimension = type switch { + ConcreteSlotValueType.Vector2 => 2, + ConcreteSlotValueType.Vector3 => 3, + ConcreteSlotValueType.Vector4 => 4, + _ => 1, + }; + + if (typeDimension > dimensionLimit) + typeDimension = dimensionLimit; + + return typeDimension switch { + 1 => "x", + 2 => "xy", + 3 => "xyz", + _ => "xyzw", + }; + } + + uint ProcessInputSlot(MaterialSlot inputSlot, string referenceName, uint maxDimensions = 4) + { + uint dimensions = 0; + + if (maxDimensions == 0) + maxDimensions = 4; + + inputSlot.hasError = false; + + // default input type + var outputConcreteType = ConcreteSlotValueType.Vector1; + + // if there is a connection + var edges = owner.GetEdges(inputSlot.slotReference); + foreach(var edge in edges) + { + if (edge != null) + { + // get the output details + var outputSlotRef = edge.outputSlot; + var outputNode = outputSlotRef.node; + if (outputNode != null) + { + var outputSlot = outputNode.FindOutputSlot(outputSlotRef.slotId); + if (outputSlot != null) + { + if (!outputSlot.hasError) + { + outputConcreteType = outputSlot.concreteValueType; + } + } + } + + break; + } + } + + var dynVectorInputSlot = inputSlot as DynamicVectorMaterialSlot; + + // get the connected output dimensions and limit it if needed + dimensions = outputConcreteType switch { + ConcreteSlotValueType.Vector2 => 2, + ConcreteSlotValueType.Vector3 => 3, + ConcreteSlotValueType.Vector4 => 4, + _ => 1, + }; + + if (dimensions > maxDimensions) + dimensions = maxDimensions; + + outputConcreteType = dimensions switch { + 2 => ConcreteSlotValueType.Vector2, + 3 => ConcreteSlotValueType.Vector3, + 4 => ConcreteSlotValueType.Vector4, + _ => ConcreteSlotValueType.Vector1 + }; + + dynVectorInputSlot.SetConcreteType(outputConcreteType); + + return dimensions; + } + + public override void EvaluateDynamicMaterialSlots(List inputSlots, List outputSlots) + { + uint slot1Dimensions = 1; + uint slot2Dimensions = 1; + uint availableDimensionsForInput2 = 4; + uint outputVectorDimensions = 0; + + // iterate over the input slots + int i = 0; + foreach (var inputSlot in inputSlots) + { + if (i == 0) + { + slot1Dimensions = ProcessInputSlot(inputSlot, kInput1SlotName, 3); + availableDimensionsForInput2 -= slot1Dimensions; + } + else if (i == 1) + { + slot2Dimensions = ProcessInputSlot(inputSlot, kInput2SlotName, availableDimensionsForInput2); + } + else + break; // No other input slots should be present + + i++; + } + + // Set the output vector dimension to the sum of the input + outputVectorDimensions = slot1Dimensions + slot2Dimensions; + foreach (var outputSlot in outputSlots) + { + (outputSlot as DynamicVectorMaterialSlot).SetConcreteType( outputVectorDimensions switch { + 2 => ConcreteSlotValueType.Vector2, + 3 => ConcreteSlotValueType.Vector3, + 4 => ConcreteSlotValueType.Vector4, + _ => ConcreteSlotValueType.Vector1 + }); + } + + CalculateNodeHasError(); + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs.meta b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs.meta new file mode 100644 index 00000000..38a320d2 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Channel/AppendVectorNode.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 34bb760e026fa494c83d62660c2c9b4a \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Advanced/PosterizeNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Advanced/PosterizeNode.cs index 204bf62a..e88cb64a 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Advanced/PosterizeNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Advanced/PosterizeNode.cs @@ -23,7 +23,7 @@ namespace UnityEditor.ShaderGraph return @" { - Out = floor(In / (1 / Steps)) * (1 / Steps); + Out = floor(In * Steps) / Steps; } "; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/FresnelEffectNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/FresnelEffectNode.cs index 3d766131..7b26caeb 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/FresnelEffectNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/FresnelEffectNode.cs @@ -26,7 +26,7 @@ namespace UnityEditor.ShaderGraph return @" { - Out = pow((1.0 - saturate(dot(normalize(Normal), normalize(ViewDir)))), Power); + Out = pow((1.0 - saturate(dot(normalize(Normal), ViewDir))), Power); } "; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/RotateAboutAxisNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/RotateAboutAxisNode.cs index 17680e2c..651cbb5b 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/RotateAboutAxisNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Math/Vector/RotateAboutAxisNode.cs @@ -50,19 +50,10 @@ namespace UnityEditor.ShaderGraph @" { Rotation = radians(Rotation); - - $precision s = sin(Rotation); - $precision c = cos(Rotation); - $precision one_minus_c = 1.0 - c; - + $precision s, c; + sincos(Rotation, s, c); Axis = normalize(Axis); - - $precision3x3 rot_mat = { one_minus_c * Axis.x * Axis.x + c, one_minus_c * Axis.x * Axis.y - Axis.z * s, one_minus_c * Axis.z * Axis.x + Axis.y * s, - one_minus_c * Axis.x * Axis.y + Axis.z * s, one_minus_c * Axis.y * Axis.y + c, one_minus_c * Axis.y * Axis.z - Axis.x * s, - one_minus_c * Axis.z * Axis.x - Axis.y * s, one_minus_c * Axis.y * Axis.z + Axis.x * s, one_minus_c * Axis.z * Axis.z + c - }; - - Out = mul(rot_mat, In); + Out = In * c + cross(Axis, In) * s + Axis * dot(Axis, In) * (1 - c); } "; } @@ -77,18 +68,10 @@ namespace UnityEditor.ShaderGraph return @" { - $precision s = sin(Rotation); - $precision c = cos(Rotation); - $precision one_minus_c = 1.0 - c; - + $precision s, c; + sincos(Rotation, s, c); Axis = normalize(Axis); - - $precision3x3 rot_mat = { one_minus_c * Axis.x * Axis.x + c, one_minus_c * Axis.x * Axis.y - Axis.z * s, one_minus_c * Axis.z * Axis.x + Axis.y * s, - one_minus_c * Axis.x * Axis.y + Axis.z * s, one_minus_c * Axis.y * Axis.y + c, one_minus_c * Axis.y * Axis.z - Axis.x * s, - one_minus_c * Axis.z * Axis.x - Axis.y * s, one_minus_c * Axis.y * Axis.z + Axis.x * s, one_minus_c * Axis.z * Axis.z + c - }; - - Out = mul(rot_mat, In); + Out = In * c + cross(Axis, In) * s + Axis * dot(Axis, In) * (1 - c); } "; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/RotateNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/RotateNode.cs index 2f98f068..fe72ac76 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/RotateNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/UV/RotateNode.cs @@ -56,22 +56,14 @@ namespace UnityEditor.ShaderGraph return @" { - //rotation matrix UV -= Center; - $precision s = sin(Rotation); - $precision c = cos(Rotation); - - //center rotation matrix - $precision2x2 rMatrix = $precision2x2(c, -s, s, c); - rMatrix *= 0.5; - rMatrix += 0.5; - rMatrix = rMatrix*2 - 1; - - //multiply the UVs by the rotation matrix - UV.xy = mul(UV.xy, rMatrix); - UV += Center; - - Out = UV; + $precision s, c; + sincos(Rotation, s, c); + $precision3 r3 = $precision3(-s, c, s); + $precision2 r1; + r1.y = dot(UV, r3.xy); + r1.x = dot(UV, r3.yz); + Out = r1 + Center; }"; } @@ -85,23 +77,15 @@ namespace UnityEditor.ShaderGraph return @" { - //rotation matrix Rotation = Rotation * (3.1415926f/180.0f); UV -= Center; - $precision s = sin(Rotation); - $precision c = cos(Rotation); - - //center rotation matrix - $precision2x2 rMatrix = $precision2x2(c, -s, s, c); - rMatrix *= 0.5; - rMatrix += 0.5; - rMatrix = rMatrix*2 - 1; - - //multiply the UVs by the rotation matrix - UV.xy = mul(UV.xy, rMatrix); - UV += Center; - - Out = UV; + $precision s, c; + sincos(Rotation, s, c); + $precision3 r3 = $precision3(-s, c, s); + $precision2 r1; + r1.y = dot(UV, r3.xy); + r1.x = dot(UV, r3.yz); + Out = r1 + Center; }"; } } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/KeywordNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/KeywordNode.cs index fe70eabc..d67ca3f4 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/KeywordNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/KeywordNode.cs @@ -132,7 +132,27 @@ namespace UnityEditor.ShaderGraph public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { var outputSlot = FindOutputSlot(OutputSlotId); - switch (keyword.keywordType) + if (keyword.keywordDefinition == KeywordDefinition.DynamicBranch) + { + switch (keyword.keywordType) + { + case KeywordType.Boolean: + var onValue = GetSlotValue(1, generationMode); + var offValue = GetSlotValue(2, generationMode); + sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)} = {keyword.referenceName} ? {onValue} : {offValue};")); + break; + case KeywordType.Enum: + sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)};")); + for(int i = 0; i < keyword.entries.Count; ++i) + { + string keywordName = $"{keyword.referenceName}_{keyword.entries[i].referenceName}"; + var value = GetSlotValue(i + 1, generationMode); + sb.AppendLine(string.Format($"{(i != 0 ? "else" : "")} if({keywordName}) {GetVariableNameForSlot(OutputSlotId)} = {value};")); + } + break; + } + } + else switch (keyword.keywordType) { case KeywordType.Boolean: { diff --git a/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordCollector.cs b/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordCollector.cs index 6ba91565..6f4dcbb8 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordCollector.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordCollector.cs @@ -8,11 +8,13 @@ namespace UnityEditor.ShaderGraph class KeywordCollector { public readonly List keywords; + public readonly List permutableKeywords; public readonly List>> permutations; public KeywordCollector() { keywords = new List(); + permutableKeywords = new(); permutations = new List>>(); } @@ -22,6 +24,9 @@ namespace UnityEditor.ShaderGraph return; keywords.Add(chunk); + + if (!chunk.IsDynamic) + permutableKeywords.Add(chunk); } public void GetKeywordsDeclaration(ShaderStringBuilder builder, GenerationMode mode) @@ -59,13 +64,14 @@ namespace UnityEditor.ShaderGraph // Initialize current permutation List> currentPermutation = new List>(); - for (int i = 0; i < keywords.Count; i++) + + for (int i = 0; i < permutableKeywords.Count; i++) { - currentPermutation.Add(new KeyValuePair(keywords[i], 0)); + currentPermutation.Add(new KeyValuePair(permutableKeywords[i], 0)); } // Recursively permute keywords - PermuteKeywords(keywords, currentPermutation, 0); + PermuteKeywords(permutableKeywords, currentPermutation, 0); } void PermuteKeywords(List keywords, List> currentPermutation, int currentIndex) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordUtil.cs b/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordUtil.cs index 602e5d67..cf65282f 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordUtil.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Util/KeywordUtil.cs @@ -72,6 +72,8 @@ namespace UnityEditor.ShaderGraph return "multi_compile"; case KeywordDefinition.ShaderFeature: return "shader_feature"; + case KeywordDefinition.DynamicBranch: + return "dynamic_branch"; default: return string.Empty; } diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs index b87dd7ca..2b2336ab 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs @@ -31,7 +31,10 @@ namespace UnityEditor.ShaderGraph.Drawing.Inspector public override string UxmlName => "GraphInspector"; public override string layoutKey => "UnityEditor.ShaderGraph.InspectorWindow"; - TabbedView m_GraphInspectorView; + TabView m_GraphInspectorView; + Tab m_GraphSettingsTab; + Tab m_NodeSettingsTab; + protected VisualElement m_GraphSettingsContainer; protected VisualElement m_NodeSettingsContainer; @@ -80,14 +83,18 @@ namespace UnityEditor.ShaderGraph.Drawing.Inspector public InspectorView(InspectorViewModel viewModel) : base(viewModel) { - m_GraphInspectorView = m_MainContainer.Q("GraphInspectorView"); + m_GraphInspectorView = m_MainContainer.Q("GraphInspectorView"); + m_GraphSettingsTab = m_GraphInspectorView.Q("GraphSettingsTab"); + m_NodeSettingsTab = m_GraphInspectorView.Q("NodeSettingsTab"); + m_GraphSettingsContainer = m_GraphInspectorView.Q("GraphSettingsContainer"); m_NodeSettingsContainer = m_GraphInspectorView.Q("NodeSettingsContainer"); m_MaxItemsMessageLabel = m_GraphInspectorView.Q