From 5fcccefe7795b56fcfc436288b85d4e13a6f301a Mon Sep 17 00:00:00 2001 From: Guillaume Levasseur Date: Thu, 16 Apr 2026 03:52:56 +0000 Subject: [PATCH 01/56] Refactor MockHMD SetupTests to allow for a wait frame after changing the eyes resolution --- .../TestRunner/HDRP_GraphicTestRunner.cs | 23 ++- .../Runtime/ConfigureMockHMD.cs | 154 ++++++++++++++---- 2 files changed, 141 insertions(+), 36 deletions(-) diff --git a/Tests/SRPTests/Packages/com.unity.testing.hdrp/TestRunner/HDRP_GraphicTestRunner.cs b/Tests/SRPTests/Packages/com.unity.testing.hdrp/TestRunner/HDRP_GraphicTestRunner.cs index efbe1c5f7f9..7010e0a5a9e 100644 --- a/Tests/SRPTests/Packages/com.unity.testing.hdrp/TestRunner/HDRP_GraphicTestRunner.cs +++ b/Tests/SRPTests/Packages/com.unity.testing.hdrp/TestRunner/HDRP_GraphicTestRunner.cs @@ -117,9 +117,9 @@ public static IEnumerator Run(SceneGraphicsTestCase testCase) // Purpose is to setup proper test aspect ratio for the camera to "see" all objects and trigger related shader compilation tasks. int warmupTime = 1; - if (XRGraphicsAutomatedTests.enabled) - warmupTime = Unity.Testing.XR.Runtime.ConfigureMockHMD.SetupTest(settings.xrCompatible, warmupTime, settings.ImageComparisonSettings); - else + Unity.Testing.XR.Runtime.ConfigureMockHMD.SetupTest(settings.xrCompatible, warmupTime, settings.ImageComparisonSettings); + + if (!XRGraphicsAutomatedTests.enabled) camera.targetTexture = RenderTexture.GetTemporary(settings.ImageComparisonSettings.TargetWidth, settings.ImageComparisonSettings.TargetHeight); // Trigger any test specific script. This is because it may change objects state and trigger shader compilation. @@ -196,7 +196,22 @@ public static IEnumerator Run(SceneGraphicsTestCase testCase) if (XRGraphicsAutomatedTests.enabled) { GraphicsTestLogger.Log(LogType.Log, "XR Automated Tests enabled."); - waitFrames = Unity.Testing.XR.Runtime.ConfigureMockHMD.SetupTest(settings.xrCompatible, waitFrames, settings.ImageComparisonSettings); + + if (settings.xrCompatible) + { + Unity.Testing.XR.Runtime.ConfigureMockHMD.ConfigureXRDisplay(settings.xrCompatible, settings.ImageComparisonSettings); + + #if !UNITY_EDITOR + // Some tests need time after eye resolution change before setting player resolution + yield return Unity.Testing.XR.Runtime.ConfigureMockHMD.WaitForXRFrames(settings.xrCompatible, 1); + #endif + + waitFrames = Unity.Testing.XR.Runtime.ConfigureMockHMD.SetPlayerResolutionForXR(settings.xrCompatible, settings.ImageComparisonSettings, waitFrames); + } + else + { + Assert.Ignore("Test scene is not compatible with XR and will be skipped."); + } // Increase tolerance to account for slight changes due to float precision settings.ImageComparisonSettings.AverageCorrectnessThreshold *= settings.xrThresholdMultiplier; diff --git a/Tests/SRPTests/Packages/com.unity.testing.xr/Runtime/ConfigureMockHMD.cs b/Tests/SRPTests/Packages/com.unity.testing.xr/Runtime/ConfigureMockHMD.cs index b4944019cc7..9d4af52220a 100644 --- a/Tests/SRPTests/Packages/com.unity.testing.xr/Runtime/ConfigureMockHMD.cs +++ b/Tests/SRPTests/Packages/com.unity.testing.xr/Runtime/ConfigureMockHMD.cs @@ -1,5 +1,8 @@ +using System.Collections; using NUnit.Framework; using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.Rendering; @@ -11,6 +14,15 @@ namespace Unity.Testing.XR.Runtime { public class ConfigureMockHMD { + /// + /// Configures MockHMD for XR testing with specified image comparison settings. + /// Sets up the XR display subsystem and configures the player resolution to match. + /// On XR, the player resolution must match the target width and target height specified in the settings. + /// + /// Whether the test scene is compatible with XR. + /// Number of frames to wait before test execution. + /// Image comparison settings containing target resolution. + /// Number of frames to wait. Returns at least 4 frames for XR eye texture resizing when XR is enabled. static public int SetupTest(bool xrCompatible, int waitFrames, UnityEngine.TestTools.Graphics.ImageComparisonSettings settings) { #if ENABLE_VR && USE_XR_MOCK_HMD @@ -18,50 +30,128 @@ static public int SetupTest(bool xrCompatible, int waitFrames, UnityEngine.TestT { if (xrCompatible) { - XRGraphicsAutomatedTests.running = true; + ConfigureXRDisplay(xrCompatible, settings); + int resolutionWaitFrames = SetPlayerResolutionForXR(xrCompatible, settings, waitFrames); - // Validate MockHMD is enabled and running - List xrDisplays = new List(); - SubsystemManager.GetSubsystems(xrDisplays); - Assume.That(xrDisplays.Count == 1 && xrDisplays[0].running, "XR display MockHMD is not running!"); + // XR plugin MockHMD requires a few frames to resize eye textures + return Mathf.Max(waitFrames, resolutionWaitFrames); + } + else + { + Assert.Ignore("Test scene is not compatible with XR and will be skipped."); + } + } +#endif + + return waitFrames; + } - // Configure MockHMD to use single-pass and compare reference image against second view (right eye) - xrDisplays[0].SetPreferredMirrorBlitMode(XRMirrorViewBlitMode.RightEye); + /// + /// Configures the XR display subsystem for MockHMD testing. + /// Sets up single-pass instanced rendering, mirror blit mode, eye resolution, and validates the display is running. + /// On XR, configures eye resolution to match the target width and target height specified in the settings. + /// Safe to call regardless of XR context - will only execute when ENABLE_VR and USE_XR_MOCK_HMD are defined and test is XR compatible. + /// + /// Whether the test scene is compatible with XR. + /// Image comparison settings containing target resolution. + static public void ConfigureXRDisplay(bool xrCompatible, UnityEngine.TestTools.Graphics.ImageComparisonSettings settings) + { + #if ENABLE_VR && USE_XR_MOCK_HMD + if (XRGraphicsAutomatedTests.enabled && xrCompatible) + { + XRGraphicsAutomatedTests.running = true; - // Configure MockHMD stereo mode - xrDisplays[0].textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray; - Unity.XR.MockHMD.MockHMD.SetRenderMode(Unity.XR.MockHMD.MockHMDBuildSettings.RenderMode.SinglePassInstanced); + var resolution = GetResolutionFromSettings(settings); - // Configure MockHMD to match the original settings from the test scene - int w = 1920; - int h = 1080; + // Validate MockHMD is enabled and running + List xrDisplays = new List(); + SubsystemManager.GetSubsystems(xrDisplays); + Assume.That(xrDisplays.Count == 1 && xrDisplays[0].running, "XR display MockHMD is not running!"); - if(!settings.UseBackBuffer) - { - w = settings.TargetWidth; - h = settings.TargetHeight; - } + // Configure MockHMD to use single-pass and compare reference image against second view (right eye) + xrDisplays[0].SetPreferredMirrorBlitMode(XRMirrorViewBlitMode.RightEye); - Unity.XR.MockHMD.MockHMD.SetEyeResolution(w, h); - Unity.XR.MockHMD.MockHMD.SetMirrorViewCrop(0.0f); + // Configure MockHMD stereo mode + xrDisplays[0].textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray; + Unity.XR.MockHMD.MockHMD.SetRenderMode(Unity.XR.MockHMD.MockHMDBuildSettings.RenderMode.SinglePassInstanced); -#if UNITY_EDITOR - UnityEditor.TestTools.Graphics.SetupGraphicsTestCases.SetGameViewSize(w, h); -#else - Screen.SetResolution(w, h, FullScreenMode.Windowed); -#endif - } - else + Unity.XR.MockHMD.MockHMD.SetEyeResolution(resolution.width, resolution.height); + Unity.XR.MockHMD.MockHMD.SetMirrorViewCrop(0.0f); + } + #endif + } + + + /// + /// Sets the player/game view resolution to match XR eye texture resolution. + /// On XR, this resolution must match the target width and target height of the test settings. + /// Safe to call regardless of XR context - will only execute when ENABLE_VR and USE_XR_MOCK_HMD are defined and test is XR compatible. + /// + /// Whether the test scene is compatible with XR. + /// Image comparison settings containing target resolution. + /// Base number of frames to wait. + /// Number of frames to wait (4) for XR eye textures to properly resize, or original waitFrames if not in XR context. + static public int SetPlayerResolutionForXR(bool xrCompatible, UnityEngine.TestTools.Graphics.ImageComparisonSettings settings, int waitFrames) + { + #if ENABLE_VR && USE_XR_MOCK_HMD + if (XRGraphicsAutomatedTests.enabled && xrCompatible) + { + XRGraphicsAutomatedTests.running = true; + + var resolution = GetResolutionFromSettings(settings); + + #if UNITY_EDITOR + UnityEditor.TestTools.Graphics.SetupGraphicsTestCases.SetGameViewSize(resolution.width, resolution.height); + #else + Screen.SetResolution(resolution.width, resolution.height, FullScreenMode.Windowed); + #endif + return Mathf.Max(waitFrames, 4); + } + #endif + return waitFrames; + } + + /// + /// Waits for the specified number of frames when XR is active and the test is XR compatible. + /// This is useful for allowing XR eye textures and display settings to properly update after configuration changes. + /// Only yields frames when ENABLE_VR and USE_XR_MOCK_HMD are defined, XRGraphicsAutomatedTests is enabled, and test is XR compatible. + /// Otherwise, completes immediately without waiting. + /// + /// Whether the test scene is compatible with XR. + /// Number of frames to wait. + /// IEnumerator for coroutine execution. + static public IEnumerator WaitForXRFrames(bool xrCompatible, int frameCount) + { + #if ENABLE_VR && USE_XR_MOCK_HMD + if (XRGraphicsAutomatedTests.enabled && xrCompatible) + { + for (int i = 0; i < frameCount; i++) { - Assert.Ignore("Test scene is not compatible with XR and will be skipped."); + yield return new WaitForEndOfFrame(); } + } + #endif + yield break; + } - // XR plugin MockHMD requires a few frames to resize eye textures - return Mathf.Max(waitFrames, 4); + /// + /// Extracts the target resolution from image comparison settings. + /// Returns the specified target width/height, or defaults to 1920x1080 if using back buffer. + /// + /// Image comparison settings. + /// Resolution as (width, height) tuple. + static private (int width, int height) GetResolutionFromSettings(UnityEngine.TestTools.Graphics.ImageComparisonSettings settings) + { + int w = 1920; + int h = 1080; + + if (!settings.UseBackBuffer) + { + w = settings.TargetWidth; + h = settings.TargetHeight; } -#endif - return waitFrames; + return (w, h); } } } From 702b3a87fcf3212f96621c776a66ecb9047a8c93 Mon Sep 17 00:00:00 2001 From: Ernestas Kupciunas Date: Thu, 16 Apr 2026 03:53:01 +0000 Subject: [PATCH 02/56] [MaterialUpgrader] Terrain and Speedtree material upgrader tests --- .../MaterialUpgraderProviders.cs | 2 + .../UniversalSpeedTree8MaterialUpgrader.cs | 2 +- .../UniversalSpeedTree9MaterialUpgrader.cs | 14 +- .../Runtime/ShaderUtils.cs | 2 +- .../SpeedTree7MaterialUpgraderTest.cs | 245 ++++++++++++ .../SpeedTree7MaterialUpgraderTest.cs.meta | 2 + .../SpeedTree8MaterialUpgraderTest.cs | 320 +++++++++++++++ .../SpeedTree8MaterialUpgraderTest.cs.meta | 2 + .../SpeedTree9MaterialUpgraderTest.cs | 374 ++++++++++++++++++ .../SpeedTree9MaterialUpgraderTest.cs.meta | 2 + .../SpeedTreeBillboardMaterialUpgraderTest.cs | 154 ++++++++ ...dTreeBillboardMaterialUpgraderTest.cs.meta | 2 + .../TerrainStandardMaterialUpgraderTest.cs | 90 +++++ ...errainStandardMaterialUpgraderTest.cs.meta | 2 + 14 files changed, 1210 insertions(+), 3 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs.meta diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/MaterialUpgraderProviders.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/MaterialUpgraderProviders.cs index 8046005f407..e4a8f4e498c 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/MaterialUpgraderProviders.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/MaterialUpgraderProviders.cs @@ -115,10 +115,12 @@ class TerrainMaterialUpgraderProvider : IMaterialUpgradersProvider { public IEnumerable GetUpgraders() { + yield return new TerrainUpgrader("Nature/Terrain/Diffuse"); yield return new TerrainUpgrader("Nature/Terrain/Standard"); yield return new SpeedTreeUpgrader("Nature/SpeedTree"); yield return new SpeedTreeBillboardUpgrader("Nature/SpeedTree Billboard"); yield return new UniversalSpeedTree8Upgrader("Nature/SpeedTree8"); + yield return new UniversalSpeedTree9Upgrader("Nature/SpeedTree9"); } } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree8MaterialUpgrader.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree8MaterialUpgrader.cs index d26163f006b..f9ab0d36523 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree8MaterialUpgrader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree8MaterialUpgrader.cs @@ -4,7 +4,7 @@ namespace UnityEditor.Rendering.Universal { - class UniversalSpeedTree8Upgrader : SpeedTree8MaterialUpgrader + class UniversalSpeedTree8Upgrader : SpeedTree8MaterialUpgrader, IBuiltInToURPMaterialUpgrader { internal UniversalSpeedTree8Upgrader(string oldShaderName) : base(oldShaderName, ShaderUtils.GetShaderPath(ShaderPathID.SpeedTree8), UniversalSpeedTree8MaterialFinalizer) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree9MaterialUpgrader.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree9MaterialUpgrader.cs index d95021dc05a..421712f16dd 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree9MaterialUpgrader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/MaterialUpgrader/UniversalSpeedTree9MaterialUpgrader.cs @@ -5,8 +5,20 @@ namespace UnityEditor.Rendering.Universal { - class UniversalSpeedTree9Upgrader : SpeedTree9MaterialUpgrader + class UniversalSpeedTree9Upgrader : SpeedTree9MaterialUpgrader, IBuiltInToURPMaterialUpgrader { + internal UniversalSpeedTree9Upgrader(string oldShaderName) + { + RenameShader(oldShaderName, "Universal Render Pipeline/Nature/SpeedTree9_URP", UniversalSpeedTree9MaterialFinalizer); + RenameFloat("_TwoSided", Property.CullMode); + RenameColor("_ColorTint", "_Color"); + RenameKeywordToFloat("EFFECT_HUE_VARIATION", "_HueVariationKwToggle", 1, 0); + RenameKeywordToFloat("EFFECT_SUBSURFACE", "_SubsurfaceKwToggle", 1, 0); + RenameKeywordToFloat("EFFECT_BUMP", "_NormalMapKwToggle", 1, 0); + RenameKeywordToFloat("EFFECT_BILLBOARD", "_BillboardKwToggle", 1, 0); + RenameKeywordToFloat("EFFECT_EXTRA_TEX", "EFFECT_EXTRA_TEX", 1, 0); + } + const int kMaterialUpgraderVersion = 1; [MaterialSettingsCallbackAttribute(kMaterialUpgraderVersion)] diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs index 17ef53262b3..04de09ef841 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs @@ -94,7 +94,7 @@ public static class ShaderUtils "Universal Render Pipeline/Nature/SpeedTree7", "Universal Render Pipeline/Nature/SpeedTree7 Billboard", "Universal Render Pipeline/Nature/SpeedTree8_PBRLit", - "SpeedTree9_Dummy_Path", // SpeedTree9 is shadergraph-only and does not have an HLSLF version, but this entry is still required + "Universal Render Pipeline/Nature/SpeedTree9_URP", // SpeedTree9 is shadergraph-only and does not have an HLSL version, but this entry is still required "Universal Render Pipeline/Complex Lit", }; diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs new file mode 100644 index 00000000000..f93dd0c8ae0 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering; +using UnityEditor.Rendering.Universal; +using UnityEngine; +using UnityEngine.TestTools; + +[Category("Graphics Tools")] + +class SpeedTree7MaterialUpgraderTest : MaterialUpgraderTestBase +{ + [OneTimeSetUp] + public override void OneTimeSetUp() + { + m_Upgrader = new SpeedTreeUpgrader("Nature/SpeedTree"); + } + + public SpeedTree7MaterialUpgraderTest() : base("Nature/SpeedTree", + "Universal Render Pipeline/Nature/SpeedTree7") + { + } + + [Test] + [TestCaseSource(nameof(MaterialUpgradeCases))] + public void UpgradeSpeedTree7Material(MaterialUpgradeTestCase testCase) + { + base.UpgradeMaterial(testCase); + } + + private static IEnumerable MaterialUpgradeCases() + { + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree7Material_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7", + setup = material => + { + // No specific setup is needed for this test case, as we are only verifying that the shader is upgraded correctly. + }, + verify = material => + { + // Verify that the shader has been upgraded to the expected SpeedTree7 shader. + Assert.AreEqual("Universal Render Pipeline/Nature/SpeedTree7", material.shader.name); + } + + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialHueVariationColorGreen_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7HueVariationColorGreenStay", + setup = material => + { + // Set the HueVariationColor property to Green before upgrading. + material.SetColor("_HueVariation", Color.green); + }, + verify = material => + { + // Verify that the HueVariationColor property is still set to Green after upgrading. + Assert.AreEqual(Color.green, material.GetColor("_HueVariation")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialColorRed_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7ColorRedStay", + setup = material => + { + // Set the Color property to Red before upgrading. + material.SetColor("_Color", Color.red); + }, + verify = material => + { + // Verify that the Color property is still set to Red after upgrading. + Assert.AreEqual(Color.red, material.GetColor("_Color")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialCullBack_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7CullBackStay", + setup = material => + { + // Set the Cull property to Back before upgrading. + material.SetFloat("_Cull", 2); + }, + verify = material => + { + // Verify that the Cull property is still set to Back after upgrading. + Assert.AreEqual(2, material.GetFloat("_Cull")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialCullOff_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7CullOffStay", + setup = material => + { + // Set the Cull property to Off before upgrading. + material.SetFloat("_Cull", 0); + }, + verify = material => + { + // Verify that the Cull property is still set to Off after upgrading. + Assert.AreEqual(0, material.GetFloat("_Cull")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialCullFront_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7CullFrontStay", + setup = material => + { + // Set the Cull property to Front before upgrading. + material.SetFloat("_Cull", 1); + }, + verify = material => + { + // Verify that the Cull property is still set to Front after upgrading. + Assert.AreEqual(1, material.GetFloat("_Cull")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityNone_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityNoneStay", + setup = material => + { + // Set the WindQuality property to None before upgrading. + material.SetFloat("_WindQuality", 0); + }, + verify = material => + { + // Verify that the WindQuality property is still set to None after upgrading. + Assert.AreEqual(0, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityFastest_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityFastestStay", + setup = material => + { + // Set the WindQuality property to Fastest before upgrading. + material.SetFloat("_WindQuality", 1); + }, + verify = material => + { + // Verify that the WindQuality property is still set to Fastest after upgrading. + Assert.AreEqual(1, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityFast_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityFastStay", + setup = material => + { + // Set the WindQuality property to Fast before upgrading. + material.SetFloat("_WindQuality", 2); + }, + verify = material => + { + // Verify that the WindQuality property is still set to Fast after upgrading. + Assert.AreEqual(2, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityBetter_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityBetterStay", + setup = material => + { + // Set the WindQuality property to Better before upgrading. + material.SetFloat("_WindQuality", 3); + }, + verify = material => + { + // Verify that the WindQuality property is still set to Better after upgrading. + Assert.AreEqual(3, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityBest_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityBestStay", + setup = material => + { + // Set the WindQuality property to Best before upgrading. + material.SetFloat("_WindQuality", 4); + }, + verify = material => + { + // Verify that the WindQuality property is still set to Best after upgrading. + Assert.AreEqual(4, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialWindQualityPalm_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7WindQualityPalmStay", + setup = material => + { + // Set the WindQuality property to Palm before upgrading. + material.SetFloat("_WindQuality", 5); + }, + verify = material => + { + // Verify that the WindQuality property is still set to Palm after upgrading. + Assert.AreEqual(5, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialGPUInstancingOn_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7GPUInstancingOnStay", + setup = material => + { + // Enable GPU Instancing before upgrading. + material.enableInstancing = true; + }, + verify = material => + { + // Verify that GPU Instancing is still enabled after upgrading. + Assert.IsTrue(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree7MaterialGPUInstancingOff_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree7GPUInstancingOffStay", + setup = material => + { + // Disable GPU Instancing before upgrading. + material.enableInstancing = false; + }, + verify = material => + { + // Verify that GPU Instancing is still disabled after upgrading. + Assert.IsFalse(material.enableInstancing); + } + }; + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs.meta new file mode 100644 index 00000000000..21283c9fbf6 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree7MaterialUpgraderTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2b11bfddec26147629f596445bf1a077 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs new file mode 100644 index 00000000000..592e0c2bfe1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering; +using UnityEditor.Rendering.Universal; +using UnityEngine; +using UnityEngine.TestTools; + +[Category("Graphics Tools")] + +class SpeedTree8MaterialUpgraderTest : MaterialUpgraderTestBase +{ + [OneTimeSetUp] + public override void OneTimeSetUp() + { + m_Upgrader = new UniversalSpeedTree8Upgrader("Nature/SpeedTree8"); + } + + public SpeedTree8MaterialUpgraderTest() : base("Nature/SpeedTree8", + "Universal Render Pipeline/Nature/SpeedTree8_PBRLit") + { + } + + [Test] + [TestCaseSource(nameof(MaterialUpgradeCases))] + public void UpgradeSpeedTree8Material(MaterialUpgradeTestCase testCase) + { + base.UpgradeMaterial(testCase); + } + + private static IEnumerable MaterialUpgradeCases() + { + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8Material_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLit", + setup = material => + { + // No specific setup is needed for this test case, as we are only verifying that the shader is upgraded correctly. + }, + verify = material => + { + Assert.AreEqual("Universal Render Pipeline/Nature/SpeedTree8_PBRLit", material.shader.name); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialColorRed_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitColorRedRemains", + setup = material => + { + // Set the Color property to Red before upgrading. + material.SetColor("_Color", Color.red); + }, + verify = material => + { + // Verify that the Color property is still set to Red after upgrading. + Assert.AreEqual(Color.red, material.GetColor("_Color")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialSmoothness01f_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitSmoothness01fRemains", + setup = material => + { + material.SetFloat("_Glossiness", 0.1f); + }, + verify = material => + { + Assert.AreEqual(0.1f, material.GetFloat("_Glossiness")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialMetallic01_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitMetallic01Remains", + setup = material => + { + material.SetFloat("_Metallic", 0.1f); + }, + verify = material => + { + Assert.AreEqual(0.1f, material.GetFloat("_Metallic")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialSubsurfaceColorBlue_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitSubsurfaceColorBlueRemains", + setup = material => + { + //set the subsurface color to blue + material.SetColor("_SubsurfaceColor", Color.blue); + }, + verify = material => + { + //verify that the subsurface color is still set to blue after upgrading + Assert.AreEqual(Color.blue, material.GetColor("_SubsurfaceColor")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityNone_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityNoneRemains", + setup = material => + { + material.SetFloat("_WindQuality", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityFastest_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityFastestRemains", + setup = material => + { + material.SetFloat("_WindQuality", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityFast_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityFastRemains", + setup = material => + { + material.SetFloat("_WindQuality", 2f); + }, + verify = material => + { + Assert.AreEqual(2f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityBetter_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityBetterRemains", + setup = material => + { + material.SetFloat("_WindQuality", 3f); + }, + verify = material => + { + Assert.AreEqual(3f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityBest_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityBestRemains", + setup = material => + { + material.SetFloat("_WindQuality", 4f); + }, + verify = material => + { + Assert.AreEqual(4f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialWindQualityPalm_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitWindQualityPalmRemains", + setup = material => + { + material.SetFloat("_WindQuality", 5f); + }, + verify = material => + { + Assert.AreEqual(5f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialHueVariationEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitHueVariationEnabledRemains", + setup = material => + { + material.EnableKeyword("EFFECT_HUE_VARIATION"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_HueVariationKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialHueVariationDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitHueVariationDisabledRemains", + setup = material => + { + material.DisableKeyword("EFFECT_HUE_VARIATION"); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_HueVariationKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialHueVariationColorRed_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitHueVariationColorRedRemains", + setup = material => + { + //set the hue variation color to red + material.SetColor("_HueVariationColor", Color.red); + }, + verify = material => + { + Assert.AreEqual(Color.red, material.GetColor("_HueVariationColor")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialSubsurfaceEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitSubsurfaceEnabledRemains", + setup = material => + { + material.EnableKeyword("EFFECT_SUBSURFACE"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_SubsurfaceKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialSubsurfaceDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitSubsurfaceDisabledRemains", + setup = material => + { + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_SubsurfaceKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialBillboardEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitBillboardEnabledRemains", + setup = material => + { + material.SetFloat("_BillboardKwToggle", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("EFFECT_BILLBOARD")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree8MaterialBillboardDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitBillboardDisabledRemains", + setup = material => + { + material.SetFloat("_BillboardKwToggle", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("EFFECT_BILLBOARD")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree8MaterialGPUInstancingOn_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitGPUInstancingOnRemains", + setup = material => + { + // Enable GPU Instancing before upgrading. + material.enableInstancing = true; + }, + verify = material => + { + // Verify that GPU Instancing is still enabled after upgrading. + Assert.IsTrue(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTree8MaterialGPUInstancingOff_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree8_PBRLitGPUInstancingOffRemains", + setup = material => + { + // Disable GPU Instancing before upgrading. + material.enableInstancing = false; + }, + verify = material => + { + // Verify that GPU Instancing is still disabled after upgrading. + Assert.IsFalse(material.enableInstancing); + } + }; + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs.meta new file mode 100644 index 00000000000..53a96bd3bec --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree8MaterialUpgraderTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8941bfe8b2cea4c5a966883eb0a8ab6a \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs new file mode 100644 index 00000000000..3e13fae2ce4 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs @@ -0,0 +1,374 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering; +using UnityEditor.Rendering.Universal; +using UnityEngine; +using UnityEngine.TestTools; + +[Category("Graphics Tools")] + +class SpeedTree9MaterialUpgraderTest : MaterialUpgraderTestBase +{ + [OneTimeSetUp] + public override void OneTimeSetUp() + { + m_Upgrader = new UniversalSpeedTree9Upgrader("Nature/SpeedTree9"); + } + + public SpeedTree9MaterialUpgraderTest() : base("Nature/SpeedTree9", + "Universal Render Pipeline/Nature/SpeedTree9_URP") + { + } + + [Test] + [TestCaseSource(nameof(MaterialUpgradeCases))] + public void UpgradeSpeedTree9Material(MaterialUpgradeTestCase testCase) + { + base.UpgradeMaterial(testCase); + } + + private static IEnumerable MaterialUpgradeCases() + { + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9Material_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URP", + setup = material => + { + // No specific setup is needed for this test case, as we are only verifying that the shader is upgraded correctly. + }, + verify = material => + { + Assert.AreEqual("Universal Render Pipeline/Nature/SpeedTree9_URP", material.shader.name); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialColorRed_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPColorRed", + setup = material => + { + // set _ColorTint to red + material.SetColor("_ColorTint", Color.red); + }, + verify = material => + { + Assert.AreEqual(Color.red, material.GetColor("_Color")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSmoothness02f_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPSmoothness02f", + setup = material => + { + material.SetFloat("_Glossiness", 0.2f); + }, + verify = material => + { + Assert.AreEqual(0.2f, material.GetFloat("_Glossiness")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialMetallic02f_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPMetallic02f", + setup = material => + { + material.SetFloat("_Metallic", 0.2f); + }, + verify = material => + { + Assert.AreEqual(0.2f, material.GetFloat("_Metallic")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSubsurfaceColorRed_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPSurfaceColorRed", + setup = material => + { + material.SetColor("_SubsurfaceColor", Color.red); + }, + verify = material => + { + Assert.AreEqual(Color.red, material.GetColor("_SubsurfaceColor")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialHueVariationEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_HueVariationEnabled", + setup = material => + { + material.EnableKeyword("EFFECT_HUE_VARIATION"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_HueVariationKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialHueVariationDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_HueVariationDisabled", + setup = material => + { + //no need because this is off by default + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_HueVariationKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialHueVariationColorRed_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_HueVariationColorRed", + setup = material => + { + //enable hue variation checkbox + material.EnableKeyword("EFFECT_HUE_VARIATION"); + //set the hue variation color to red + material.SetColor("_HueVariationColor", Color.red); + }, + verify = material => + { + Assert.AreEqual(Color.red, material.GetColor("_HueVariationColor")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_Speedtree9MaterialNormalMapEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_NormalMapEnabled", + setup = material => + { + material.EnableKeyword("EFFECT_BUMP"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_NormalMapKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialNormalMapDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_NormalMapDisabled", + setup = material => + { + material.DisableKeyword("EFFECT_BUMP"); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_NormalMapKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSubsurfaceEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPSubsurfaceEnabled", + setup = material => + { + material.EnableKeyword("EFFECT_SUBSURFACE"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_SubsurfaceKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSubsurfaceDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_URPSubsurfaceDisabled", + setup = material => + { + //no need to check, because it is off by default + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_SubsurfaceKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBillboardEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_BillboardEnabled", + setup = material => + { + material.EnableKeyword("EFFECT_BILLBOARD"); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_BillboardKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBillboardDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_BillboardDisabled", + setup = material => + { + material.DisableKeyword("EFFECT_BILLBOARD"); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_BillboardKwToggle")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSharedMotionEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_MotionEnabled", + setup = material => + { + material.SetFloat("_WIND_SHARED", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_WIND_SHARED")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialSharedMotionDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_MotionDisabled", + setup = material => + { + material.SetFloat("_WIND_SHARED", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_WIND_SHARED")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBranch1MotionEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_Branch1MotionEnabled", + setup = material => + { + material.SetFloat("_WIND_BRANCH1", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_WIND_BRANCH1")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBranch1MotionDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_Branch1MotionDisabled", + setup = material => + { + material.SetFloat("_WIND_BRANCH1", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_WIND_BRANCH1")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBranch2MotionEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_Branch2MotionEnabled", + setup = material => + { + material.SetFloat("_WIND_BRANCH2", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_WIND_BRANCH2")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialBranch2MotionDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_Branch2MotionDisabled", + setup = material => + { + material.SetFloat("_WIND_BRANCH2", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_WIND_BRANCH2")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialRippleMotionEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_RippleMotionEnabled", + setup = material => + { + material.SetFloat("_WIND_RIPPLE", 1f); + }, + verify = material => + { + Assert.AreEqual(1f, material.GetFloat("_WIND_RIPPLE")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialRippleMotionDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_RippleMotionDisabled", + setup = material => + { + material.SetFloat("_WIND_RIPPLE", 0f); + }, + verify = material => + { + Assert.AreEqual(0f, material.GetFloat("_WIND_RIPPLE")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialGPUInstancingEnabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_GPUInstancingEnabled", + setup = material => + { + material.enableInstancing = true; + }, + verify = material => + { + Assert.IsTrue(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTree9MaterialGPUInstancingDisabled_WhenUpgrading_Then_TheShaderUpgradedToUniversalRenderPipelineSpeedTree9_GPUInstancingDisabled", + setup = material => + { + material.enableInstancing = false; + }, + verify = material => + { + Assert.IsFalse(material.enableInstancing); + } + }; + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs.meta new file mode 100644 index 00000000000..054402457e0 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTree9MaterialUpgraderTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1e2111b050c0b4ff993323691eab7ce6 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs new file mode 100644 index 00000000000..579a80d055f --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering; +using UnityEditor.Rendering.Universal; +using UnityEngine; +using UnityEngine.TestTools; + +[Category("Graphics Tools")] + +class SpeedTreeBillboardMaterialUpgraderTest : MaterialUpgraderTestBase +{ + [OneTimeSetUp] + public override void OneTimeSetUp() + { + m_Upgrader = new SpeedTreeBillboardUpgrader("Nature/SpeedTree Billboard"); + } + + public SpeedTreeBillboardMaterialUpgraderTest() : base("Nature/SpeedTree Billboard", + "Universal Render Pipeline/Nature/SpeedTree7 Billboard") + { + } + + [Test] + [TestCaseSource(nameof(MaterialUpgradeCases))] + public void UpgradeSpeedTree7BillboardMaterial(MaterialUpgradeTestCase testCase) + { + base.UpgradeMaterial(testCase); + } + + private static IEnumerable MaterialUpgradeCases() + { + yield return new MaterialUpgradeTestCase + { + name = + "Given_SpeedTreeBillboardMaterial_When_Upgrading_Then_ShaderIsUpgradedToSpeedTree7Billboard", + setup = material => + { + // No specific setup is needed for this test case, as we are only verifying that the shader is upgraded correctly. + }, + verify = material => + { + // Verify that the shader has been upgraded to the expected shader. + Assert.AreEqual("Universal Render Pipeline/Nature/SpeedTree7 Billboard", material.shader.name); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialMainColorRed_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardMainColorIsRed", + setup = material => + { + // Set the main color to red before upgrading. + material.SetColor("_Color", Color.red); + }, + verify = material => + { + // Verify that the main color is still red after upgrading. + Assert.AreEqual(Color.red, material.GetColor("_Color")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialHueVariationGreen_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardHueVariationIsGreen", + setup = material => + { + // Set the hue variation to green before upgrading. + material.SetColor("_HueVariation", Color.green); + }, + verify = material => + { + // Verify that the hue variation is still green after upgrading. + Assert.AreEqual(Color.green, material.GetColor("_HueVariation")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialAlphaCutoff02_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardAlphaCutoffIs02", + setup = material => + { + // Set the alpha cutoff to 0.2 before upgrading. + material.SetFloat("_Cutoff", 0.2f); + }, + verify = material => + { + // Verify that the alpha cutoff is still 0.2 after upgrading. + Assert.AreEqual(0.2f, material.GetFloat("_Cutoff")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialWindQualityNone_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardWindQualityIsNone", + setup = material => + { + // Set the wind quality to none before upgrading. + material.SetFloat("_WindQuality", 0.0f); + }, + verify = material => + { + // Verify that the wind quality is still none after upgrading. + Assert.AreEqual(0.0f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialWindQualityFastest_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardWindQualityIsFastest", + setup = material => + { + // Set the wind quality to fastest before upgrading. + material.SetFloat("_WindQuality", 1.0f); + }, + verify = material => + { + // Verify that the wind quality is still fastest after upgrading. + Assert.AreEqual(1.0f, material.GetFloat("_WindQuality")); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialGPUInstancingEnabled_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardGPUInstancingIsEnabled", + setup = material => + { + // Enable GPU instancing before upgrading. + material.enableInstancing = true; + }, + verify = material => + { + // Verify that GPU instancing is still enabled after upgrading. + Assert.IsTrue(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = "Given_SpeedTreeBillboardMaterialGPUInstancingDisabled_When_Upgrading_Then_TheShaderUniversalRenderPipelineSpeedTree7BillboardGPUInstancingIsDisabled", + setup = material => + { + // Disable GPU instancing before upgrading. + material.enableInstancing = false; + }, + verify = material => + { + // Verify that GPU instancing is still disabled after upgrading. + Assert.IsFalse(material.enableInstancing); + } + }; + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs.meta new file mode 100644 index 00000000000..276fa4e5894 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/SpeedTreeBillboardMaterialUpgraderTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c02aaa6d0029641a3ac439699edf6648 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs new file mode 100644 index 00000000000..c1f8ce4a7c8 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering; +using UnityEditor.Rendering.Universal; +using UnityEngine; +using UnityEngine.TestTools; + +[Category("Graphics Tools")] + +class TerrainStandardMaterialUpgraderTest : MaterialUpgraderTestBase +{ + [OneTimeSetUp] + public override void OneTimeSetUp() + { + m_Upgrader = new TerrainUpgrader("Nature/Terrain/Standard"); + } + + public TerrainStandardMaterialUpgraderTest() : base("Nature/Terrain/Standard", + "Universal Render Pipeline/Terrain/Lit") + { + } + + [Test] + [TestCaseSource(nameof(MaterialUpgradeCases))] + public void UpgradeTerrainStandardMaterial(MaterialUpgradeTestCase testCase) + { + base.UpgradeMaterial(testCase); + } + + private static IEnumerable MaterialUpgradeCases() + { + yield return new MaterialUpgradeTestCase + { + name = + "Given_TerrainStandardMaterial_When_Upgrading_Then_TheShaderUpgradedToUniversalRenderPipelineTerrainLit", + setup = material => + { + // No specific setup is needed for this test case, as we are only verifying that the shader is upgraded correctly. + }, + verify = material => + { + Assert.AreEqual("Universal Render Pipeline/Terrain/Lit", material.shader.name); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_TerrainStandardMaterialEnabledInstancing_When_Upgrading_Then_TheInstancingEnabled", + setup = material => + { + material.enableInstancing = true; + }, + verify = material => + { + Assert.IsTrue(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_TerrainStandardMaterialDisabledInstancing_When_Upgrading_Then_TheInstancingDisabled", + setup = material => + { + material.enableInstancing = false; + }, + verify = material => + { + Assert.IsFalse(material.enableInstancing); + } + }; + + yield return new MaterialUpgradeTestCase + { + name = + "Given_TerrainStandardMaterialLodFadeCrossFadeEnabled_When_Upgrading_Then_TheLodFadeCrossFadeDisabled", + setup = material => + { + material.EnableKeyword("LOD_FADE_CROSSFADE"); + }, + verify = material => + { + Assert.IsFalse(material.IsKeywordEnabled("LOD_FADE_CROSSFADE")); + } + }; + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs.meta new file mode 100644 index 00000000000..678ed1cfe13 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/MaterialUpgrader/TerrainStandardMaterialUpgraderTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a9d1fb7138470405fbb45b1154051aa5 \ No newline at end of file From b2781b4a4c45c7ca6b17493f121fe6bc5bf698d1 Mon Sep 17 00:00:00 2001 From: Sasha Slobodov Date: Thu, 16 Apr 2026 20:44:51 +0000 Subject: [PATCH 03/56] [content automatically redacted] touching PlatformDependent folder --- .../Editor/Lighting/ProbeVolume/ProbeGIBaking.cs | 1 + 1 file changed, 1 insertion(+) 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 f2bcb0a0077..1ce93cfc1bd 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 @@ -892,6 +892,7 @@ static internal void Init() Lightmapping.bakeStarted += OnBakeStarted; Lightmapping.bakeCancelled += OnBakeCancelled; Lightmapping.inputExtraction += OnInputExtraction; + AssemblyReloadEvents.beforeAssemblyReload += CleanUp; } } From 4da5fb1a313bdc892678064e3202b645f40cc694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Duverne?= Date: Thu, 16 Apr 2026 20:44:56 +0000 Subject: [PATCH 04/56] Reference pages for new Shader Graph nodes: Expression and Switch --- .../Documentation~/Create-Node-Menu.md | 2 +- .../Documentation~/Expression-Node.md | 31 ++++++++++++++++ .../Documentation~/First-Shader-Graph.md | 2 +- .../Documentation~/Switch-Node.md | 37 +++++++++++++++++++ .../Documentation~/TableOfContents.md | 2 + .../Documentation~/Utility-Nodes.md | 36 +++++++++--------- 6 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 Packages/com.unity.shadergraph/Documentation~/Expression-Node.md create mode 100644 Packages/com.unity.shadergraph/Documentation~/Switch-Node.md diff --git a/Packages/com.unity.shadergraph/Documentation~/Create-Node-Menu.md b/Packages/com.unity.shadergraph/Documentation~/Create-Node-Menu.md index 5cfbb956fbc..011ab4a6cec 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Create-Node-Menu.md +++ b/Packages/com.unity.shadergraph/Documentation~/Create-Node-Menu.md @@ -29,7 +29,7 @@ To connect [ports](Port.md) between two existing [nodes](Node.md) or with the [m The line resulting from that connection is called an [edge](Edge.md). -You can only connect an output port to a input port, or vice-versa, and you can't connect two ports of the same node together. +You can only connect an output port to an input port, or vice-versa, and you can't connect two ports of the same node together. ## Add and connect a node from an existing port diff --git a/Packages/com.unity.shadergraph/Documentation~/Expression-Node.md b/Packages/com.unity.shadergraph/Documentation~/Expression-Node.md new file mode 100644 index 00000000000..b5f16f0adce --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Expression-Node.md @@ -0,0 +1,31 @@ +# Expression node + +Use the Expression node to specify a complex mathematical expression as a string instead of using multiple [Math nodes](Math-Nodes.md). + +## Input ports + +The number and type of input ports automatically adjust to the values of the [node controls](#controls). Unity adds an input port for each variable in the expression in the text field. + +## Output port + +| **Name** | **Type** | **Description** | +| :--- | :--- | :--- | +| **Out** | Depends on the selected **Type** in the [node controls](#controls). | The value resulting from the expression specified in the text field. | + +## Controls + +| **Name** | **Description** | +| :--- | :--- | +| **Type** | Specifies the data type to use for all input and output ports of the node. The options are:
  • **Vector 1**
  • **Vector 2**
  • **Vector 3**
  • **Vector 4**
| +| (Text field) | Use this field to specify the mathematical expression. The field supports the following:
  • Math operators: `+`, `-`, `*`, `/`, and parentheses.
  • HLSL intrinsic functions: for example, `frac` and `saturate`.
  • Vector swizzling: for example, `a.xw`.
  • Vector construction: `float2(x, y)`.
| + +## Example + +If you specify the expression: + +`a + b * c / 2` + +* Unity adds three input ports to the node: **A**, **B**, and **C**. +* If you input 1, 2, and 10, the node calculates `1 + 2 * 10 / 2` and outputs the result to the **Out** port. + +**Note**: If you use Shader Graph math nodes instead, the example requires three separate nodes: [Divide](Divide-Node.md), [Multiply](Multiply-Node.md), and [Add](Add-Node.md). \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/First-Shader-Graph.md b/Packages/com.unity.shadergraph/Documentation~/First-Shader-Graph.md index 240330c6fd7..f8325607a00 100644 --- a/Packages/com.unity.shadergraph/Documentation~/First-Shader-Graph.md +++ b/Packages/com.unity.shadergraph/Documentation~/First-Shader-Graph.md @@ -108,7 +108,7 @@ To use a Color property instead of a Color node in your shader graph, follow the 1. Save your graph, and return to the material's Inspector. - The property you added in the graph now appears in the material's Inspector. Any changes you make to the property from the Inspector affects all objects that use this material. + The property you added to the graph now appears in the material's Inspector. Any changes you make to the property from the Inspector affect all objects that use this material. ## Additional resources diff --git a/Packages/com.unity.shadergraph/Documentation~/Switch-Node.md b/Packages/com.unity.shadergraph/Documentation~/Switch-Node.md new file mode 100644 index 00000000000..a301a419c63 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Switch-Node.md @@ -0,0 +1,37 @@ +# Switch node + +Use the Switch node to branch based on different cases with value comparisons. + +## Input ports + +| **Name** | **Type** | **Description** | +| :--- | :--- | :--- | +| **Predicate** | Float | The value to test against the conditions. | +| **Fallback** | Dynamic | The fallback value when the **Predicate** doesn't meet any of the conditions. | + +The other input ports allow you to input different branches for each condition you set up for the node. The presence, number and order of these ports depend on the way you set up the conditions. Use one of the two following options: + +* Set up conditions within the node in the [Node settings](#node-settings) through the **Conditions** table. + +* Set up conditions through a [**Float** Property](Property-Types.md#float) you configure as an **Enum** and connect to the **Predicate** port. + +## Output port + +| **Name** | **Type** | **Description** | +| :--- | :--- | :--- | +| **Out** | Dynamic | The value from the input port that the **Predicate** meets the condition of, otherwise the value from the **Fallback** input port. | + +## Node settings + +| **Name** | **Description** | +| :--- | :--- | +| **Floor Predicate** | Rounds down the value of the predicate before testing it against the conditions.
Enable this property to make sure the node still outputs values when the **Predicate** doesn't exactly match a **Condition**. | +| **Conditions** | Defines the list of conditions within the node and creates the corresponding input ports.
To add a [condition](#condition), select **Add** (+).

**Note**: If you connect a **Float** Property configured as an **Enum** to the **Predicate** port, the Switch node ignores the **Conditions** list and uses the **Entries** of the connected Property instead. | + +### Condition + +| **Name** | **Description** | +| :--- | :--- | +| **Name** | The condition's name, which Unity also uses as the name for the corresponding input port. Unity automatically names the conditions with letters in alphabetical order and you can't edit them. | +| **Type** | The type of comparison to make between the **Predicate** and the condition's **Value**. The options are:
  • Equal
  • Not Equal
  • Less
  • Less Or Equal
  • Greater
  • Greater Or Equal
| +| **Value** | The value to test the **Predicate** against, according to the condition's **Type**. | diff --git a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md index 6fac9b7bfc4..bd722e7a769 100644 --- a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md +++ b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md @@ -289,6 +289,7 @@ * [Sample Element Texture](sample-element-texture-node.md) * [Utility](Utility-Nodes.md) * [Custom Function](Custom-Function-Node.md) + * [Expression](Expression-Node.md) * [Preview](Preview-Node.md) * High Definition Render Pipeline * [Emission](Emission-Node.md) @@ -318,6 +319,7 @@ * [Nand](Nand-Node.md) * [Not](Not-Node.md) * [Or](Or-Node.md) + * [Switch](Switch-Node.md) * [UV](UV-Nodes.md) * [Flipbook](Flipbook-Node.md) * [Parallax Mapping](Parallax-Mapping-Node.md) diff --git a/Packages/com.unity.shadergraph/Documentation~/Utility-Nodes.md b/Packages/com.unity.shadergraph/Documentation~/Utility-Nodes.md index fdf7276670c..b757964c4fb 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Utility-Nodes.md +++ b/Packages/com.unity.shadergraph/Documentation~/Utility-Nodes.md @@ -1,23 +1,25 @@ # Utility nodes -Enable essential logic operations, previews, and sub-graph referencing. +Explore nodes that enable essential logic operations, customization with HLSL, complex math expressions, and previews. -| **Topic** | **Description** | -|--------------------------------|------------------------------------------------------------------------------------| -| [Preview](Preview-Node.md) | Provides a preview window and passes the input value through without modification. | -| [Sub-Graph](Sub-graph-Node.md) | Provides a reference to a Sub-graph asset. | +| **Topic** | **Description** | +| :--- | :--- | +| [Custom Function](Custom-Function-Node.md) | Returns the results of a custom HLSL function specified as a string or in a referenced file. | +| [Expression](Expression-Node.md) | Returns the result of a custom mathematical expression specified as a string. | +| [Preview](Preview-Node.md) | Provides a preview window and passes the input value through without modification. | ## Logic -| **Topic** | **Description** | -|------------------------------------|---------------------------------------------------------------------------------------------------| -| [All](All-Node.md) | Returns true if all components of the input In are non-zero. | -| [And](And-Node.md) | Returns true if both the inputs A and B are true. | -| [Any](Any-Node.md) | Returns true if any of the components of the input In are non-zero. | -| [Branch](Branch-Node.md) | Provides a dynamic branch to the shader. | -| [Comparison](Comparison-Node.md) | Compares the two input values A and B based on the condition selected on the dropdown. | -| [Is Infinite](Is-Infinite-Node.md) | Returns true if any of the components of the input In is an infinite value. | -| [Is NaN](Is-NaN-Node.md) | Returns true if any of the components of the input In is not a number (NaN). | -| [Nand](Nand-Node.md) | Returns true if both the inputs A and B are false. | -| [Not](Not-Node.md) | Returns the opposite of input In. If In is true, the output is false. Otherwise, it returns true. | -| [Or](Or-Node.md) | Returns true if either input A or input B is true. | +| **Topic** | **Description** | +| :--- | :--- | +| [All](All-Node.md) | Returns true if all components of the input In are non-zero. | +| [And](And-Node.md) | Returns true if both the inputs A and B are true. | +| [Any](Any-Node.md) | Returns true if any of the components of the input In are non-zero. | +| [Branch](Branch-Node.md) | Provides a dynamic branch to the shader. | +| [Comparison](Comparison-Node.md) | Compares the two input values A and B based on the condition selected on the dropdown. | +| [Is Infinite](Is-Infinite-Node.md) | Returns true if any of the components of the input In is an infinite value. | +| [Is NaN](Is-NaN-Node.md) | Returns true if any of the components of the input In is not a number (NaN). | +| [Nand](Nand-Node.md) | Returns true if both the inputs A and B are false. | +| [Not](Not-Node.md) | Returns the opposite of input In. If In is true, the output is false. Otherwise, it returns true. | +| [Or](Or-Node.md) | Returns true if either input A or input B is true. | +| [Switch](Switch-Node.md) | Enables branching based on different cases with value comparisons. | From 0ceffbd561e1f4e62175390bbf0963c59b2b8e30 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Thu, 16 Apr 2026 20:45:02 +0000 Subject: [PATCH 05/56] Fixed display stats not updating until tab switch in the runtime debug UI --- .../Runtime/Debugging/RuntimeDebugWindow.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs index cb4e0649a00..3d47460f623 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs @@ -127,7 +127,9 @@ void BuildDebugUI() else selectedPanelName = m_SelectedPanel.displayName; - SetSelectedPanel(selectedPanelName); + // Defer until after layout so all AttachToPanelEvent callbacks from ScheduleTracked + // have fired and registered their schedulers before SetHierarchyEnabled is called. + m_TabViewElement.schedule.Execute(_ => SetSelectedPanel(selectedPanelName)).StartingIn(100); } void OnDestroy() From d3e8bfb05c2914905e90c49366bbf17e79a73b83 Mon Sep 17 00:00:00 2001 From: Jed Lang Date: Thu, 16 Apr 2026 20:45:05 +0000 Subject: [PATCH 06/56] Graphics/srp/fix/fix broken swap function uum 139463 --- .../Textures/BufferedRTHandleSystem.cs | 4 +- .../Editor/BufferedRTHandleSystemTests.cs | 60 +++++++++++++++++++ .../BufferedRTHandleSystemTests.cs.meta | 2 + 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs index 96a948556e8..5b454ebc084 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs @@ -239,8 +239,8 @@ void Swap() if (item.Value.Length > 1) { var nextFirst = item.Value[item.Value.Length - 1]; - for (int i = 0, c = item.Value.Length - 1; i < c; ++i) - item.Value[i + 1] = item.Value[i]; + for (int i = item.Value.Length - 1; i > 0; --i) + item.Value[i] = item.Value[i - 1]; item.Value[0] = nextFirst; // First is autoresize, other are on demand diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs new file mode 100644 index 00000000000..d9d0da50123 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs @@ -0,0 +1,60 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.Experimental.Rendering; + +namespace UnityEngine.Rendering.Tests +{ + class BufferedRTHandleSystemTests + { + [Test, NUnit.Framework.Property("Jira", "UUM-139463")] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + public void BuffersSwapIntoCorrectPositions(int bufferCount) + { + const int BufferId = 10; + + RTHandle Allocator(RTHandleSystem rtHandleSystem, int frameIndex) + { + return rtHandleSystem.Alloc( + Vector2.one, 1, + colorFormat: GraphicsFormat.R8G8B8A8_UNorm, + dimension: TextureDimension.Tex2D, + name: $"Frame Buffer {frameIndex}"); + } + + using var rtHandleSys = new Rendering.BufferedRTHandleSystem(); + + // Allocate buffers + rtHandleSys.AllocBuffer(BufferId, Allocator, bufferCount); + + // Record order of buffers before swap + var preBufferOrder = new RTHandle[bufferCount]; + for (var i = 0; i < bufferCount; ++i) + { + preBufferOrder[i] = rtHandleSys.GetFrameRT(BufferId, i); + } + + // Perform swap + rtHandleSys.SwapAndSetReferenceSize(256, 256); + + // Record order of buffers after swap + var postBufferOrder = new RTHandle[bufferCount]; + for (var i = 0; i < bufferCount; ++i) + { + postBufferOrder[i] = rtHandleSys.GetFrameRT(BufferId, i); + } + + // Compare before/after buffer orders + for (var i = 0; i < bufferCount - 1; ++i) + { + // First length-1 elements + Assert.AreEqual(preBufferOrder[i], postBufferOrder[i + 1]); + } + // Last element + Assert.AreEqual(preBufferOrder[bufferCount - 1], postBufferOrder[0]); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs.meta new file mode 100644 index 00000000000..e40a22d280b --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/BufferedRTHandleSystemTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 72ba1b3f59e3718449ade1f386be4a93 \ No newline at end of file From b1e0fa73936c59a74e670dad79dfcf715392938c Mon Sep 17 00:00:00 2001 From: Ludovic Theobald Date: Fri, 17 Apr 2026 07:18:52 +0000 Subject: [PATCH 07/56] [VFX New Compiler] Nested structured / unordered data --- .../DataDescriptionWriterRegistry.cs | 2 +- .../Compiler/Passes/DataLayoutPass.cs | 195 ++++++++++++++++++ ...outPass.cs.meta => DataLayoutPass.cs.meta} | 0 .../Passes/StructuredDataLayoutPass.cs | 193 ----------------- .../Data/Description/StructuredData.cs | 24 +-- .../Data/Description/StructuredData.cs.meta | 3 +- .../Data/Description/UnorderedData.cs | 46 +++++ .../Data/Description/UnorderedData.cs.meta | 2 + .../StructuredDataDescriptionWriter.cs | 36 ++-- .../StructuredDataDescriptionWriter.cs.meta | 3 +- .../Data/IDataDescriptionWriter.cs | 2 +- .../Editor/GraphCommon/Task/TemplatedTask.cs | 8 +- .../ParticleSystemDataDescriptionWriter.cs | 2 +- .../Passes/VfxGraphLegacyOutputPass.cs | 51 +++-- .../Editor/NewCompiler/VfxGraphCompiler.cs | 2 +- .../VfxIntermediateGraphBuilder.cs | 65 ++++-- .../Shaders/Temp/Templates/Init.hlsl | 4 +- .../Shaders/Temp/Templates/Update.hlsl | 2 +- 18 files changed, 373 insertions(+), 267 deletions(-) create mode 100644 Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs rename Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/{StructuredDataLayoutPass.cs.meta => DataLayoutPass.cs.meta} (100%) delete mode 100644 Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs create mode 100644 Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs create mode 100644 Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs.meta diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/DataDescriptionWriterRegistry.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/DataDescriptionWriterRegistry.cs index f259dfb2748..5c686e5cd69 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/DataDescriptionWriterRegistry.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/DataDescriptionWriterRegistry.cs @@ -21,7 +21,7 @@ public bool TryGetDataDescriptionWriter(IDataDescription dataDescription, out ID public string GetSubdataName(DataView dataView, IDataKey subDataKey) { - return m_Writers.TryGetValue(dataView.DataDescription.GetType(), out var writer) ? writer.GetSubdataName(subDataKey) : null; + return m_Writers.TryGetValue(dataView.DataDescription.GetType(), out var writer) ? writer.GetSubdataName(dataView, subDataKey) : null; } public string GetSubdataTypeName(DataView dataView, IDataKey subDataKey) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs new file mode 100644 index 00000000000..d1177f7cc5e --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Unity.GraphCommon.LowLevel.Editor +{ + class DataLayoutPass : CompilationPass + { + public bool Execute(ref CompilationContext context) + { + DataLayoutContainer dataLayoutContainer = context.data.GetOrCreate(); + + foreach (var dataContainer in context.graph.DataContainers) + { + if (dataContainer.RootDataView.DataDescription is UnorderedData or StructuredData) + { + ConcreteLayout concreteLayout = GenerateBufferLayout(dataContainer.RootDataView.DataDescription); + dataLayoutContainer.TryAddLayout(dataContainer.Id, concreteLayout); + } + } + + foreach (var dataView in context.graph.DataViews) + { + if (dataView.DataDescription is UnorderedData unorderedData) + { + //if Unordered, override dataContainer.RootDataView.DataDescription with a StructuredData. + //Unordered is treated like an abstract data description that can be converted to a structured one with the right layout. + + StructuredData structuredData = new StructuredData(); + foreach (var (key, data) in unorderedData.SubDatas) + { + structuredData.AddSubdata(key, data); + } + context.graph.OverrideDataDescription(dataView.Id, structuredData); + } + } + return true; + } + + ConcreteLayout GenerateBufferLayout(IDataDescription dataDescription) + { + ConcreteLayout concreteLayout; + switch (dataDescription) + { + case UnorderedData unorderedData: + concreteLayout = ConcreteLayout.FromUnordered(GenerateChildLayouts(unorderedData.SubDataDescriptions)); + break; + case StructuredData structuredData: + concreteLayout = ConcreteLayout.FromStructured(GenerateChildLayouts(structuredData.SubDataDescriptions)); + break; + case ValueData valueData: + concreteLayout = new ConcreteLayout(valueData); + break; + default: + // If the data description is of an unknown type, assert with a message and return null + Debug.Assert(false, $"Unknown data description type for buffer layout: {dataDescription.GetType()}"); + return null; + } + return concreteLayout; + } + + List GenerateChildLayouts(IEnumerable children) + { + var layouts = new List(); + foreach (var child in children) + layouts.Add(GenerateBufferLayout(child)); + return layouts; + } + } + + class ConcreteLayout + { + public int Size { get; private set; } + private Dictionary m_ValueDataOffsets = new(); + + public ConcreteLayout(ValueData valueData) + { + m_ValueDataOffsets.Add(valueData, 0); + Size = DataLayoutHelper.ValueSize(valueData); + } + + public ConcreteLayout() + { + Size = 0; + } + + public static ConcreteLayout FromStructured(List children) + { + var layout = new ConcreteLayout(); + foreach (var child in children) + layout.AppendSubLayout(child); + return layout; + } + + public static ConcreteLayout FromUnordered(List children) + { + // Bucket-pack children into 4-word aligned buckets + var buckets = new List>(); + var bucketSizes = new List(); + + foreach (var child in children) + { + bool added = false; + for (int i = 0; i < buckets.Count; i++) + { + if (bucketSizes[i] + child.Size <= 4 /*kAlignment*/) + { + buckets[i].Add(child); + bucketSizes[i] += child.Size; + added = true; + break; + } + } + if (!added) + { + buckets.Add(new List { child }); + bucketSizes.Add(child.Size); + } + } + + var layout = new ConcreteLayout(); + foreach (var bucket in buckets) + { + foreach (var child in bucket) + layout.AppendSubLayout(child); + layout.PadSize(); + } + return layout; + } + + public void AppendSubLayout(ConcreteLayout subLayout) + { + int currentSize = Size; + foreach (var kvp in subLayout.m_ValueDataOffsets) + { + m_ValueDataOffsets.Add(kvp.Key, kvp.Value + currentSize); + } + Size += subLayout.Size; + } + + public void PadSize() + { + if(Size % 4 != 0) + { + Size += 4 - (Size % 4); + } + } + + public string DebugString() + { + string result = $"ConcreteLayout(Size: {Size}, ValueDataOffsets: {{"; + foreach (var kvp in m_ValueDataOffsets) + result += $"{kvp.Key.Type.Name}: {kvp.Value}, "; + result += "})"; + return result; + } + + public uint GetBufferSize() + { + return (uint)Size; + } + + public int GetValueOffset(ValueData valueData) + { + if (m_ValueDataOffsets.Count == 0) + { + throw new Exception("Value data offsets have not been initialized."); + } + return m_ValueDataOffsets.GetValueOrDefault(valueData, -1); + } + } + + class DataLayoutContainer + { + Dictionary m_DataValueLayouts = new(); + + internal bool TryGetLayout(DataContainerId dataContainerId, out ConcreteLayout layout) + { + return m_DataValueLayouts.TryGetValue(dataContainerId, out layout); + } + + public bool TryAddLayout(DataContainerId dataContainerId, ConcreteLayout concreteLayout) + { + return m_DataValueLayouts.TryAdd(dataContainerId, concreteLayout); + } + } + + static class DataLayoutHelper + { + public static int ValueSize(ValueData valueData) + { + return System.Runtime.InteropServices.Marshal.SizeOf(valueData.Type) / sizeof(uint); + } + } +} diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs.meta similarity index 100% rename from Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs.meta rename to Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs.meta diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs deleted file mode 100644 index 2018477c707..00000000000 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/StructuredDataLayoutPass.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Unity.GraphCommon.LowLevel.Editor -{ - class StructuredDataLayoutPass : CompilationPass - { - public bool Execute(ref CompilationContext context) - { - StructuredDataLayoutContainer structuredDataLayoutContainer = context.data.GetOrCreate(); - - foreach (var dataView in context.graph.DataViews) - { - if (dataView.DataDescription is StructuredData structuredData) - { - ValueBufferLayout valueBufferLayout = structuredDataLayoutContainer.CreateLayout(structuredData); - foreach (var subData in structuredData.SubDataDescriptions) - { - if (subData is ValueData valueData && !typeof(Texture).IsAssignableFrom(valueData.Type)) - { - valueBufferLayout.AddValueData(valueData); - } - } - valueBufferLayout.ComputeOffsets(); - } - } - return true; - } - } - - - - class ValueBufferLayout - { - private List m_ValueDatas = new(); - private Dictionary m_ValueDataOffsets = new(); - private List m_BucketedValueDatas = new(); - private int m_TotalSize; - private static readonly int kAlignement = 4; - - public IEnumerable ValueDatas => m_ValueDatas; - - public uint GetBufferSize() - { - if (m_ValueDataOffsets.Count == 0) - { - throw new Exception("Value data offsets have not been initialized."); - } - - return (uint)m_TotalSize; - } - - public void AddValueData(ValueData value) - { - m_ValueDatas.Add(value); - } - - public int GetValueOffset(ValueData valueData) - { - if (m_ValueDataOffsets.Count == 0) - { - throw new Exception("Value data offsets have not been initialized."); - } - - return m_ValueDataOffsets.GetValueOrDefault(valueData, -1); - } - - public bool ContainsValueData(ValueData valueData) - { - return m_ValueDataOffsets.ContainsKey(valueData); - } - - struct OffsetValueData - { - public ValueData ValueData { get; } - public int OffsetInBucket { get; } - - public OffsetValueData(ValueData valueData, int offsetInBucket) - { - ValueData = valueData; - OffsetInBucket = offsetInBucket; - } - } - class Bucket - { - List m_BucketValueDatas; - int m_CurrentSize; - - public Bucket(ValueData valueData) - { - m_BucketValueDatas = new List(); - m_BucketValueDatas.Add(new OffsetValueData(valueData, 0)); - int valueSize = ValueSize(valueData); - m_CurrentSize = valueSize; - } - - public bool TryAdd(ValueData valueData) - { - int valueSize = ValueSize(valueData); - if(m_CurrentSize + valueSize <= kAlignement) - { - m_BucketValueDatas.Add(new OffsetValueData(valueData, m_CurrentSize)); - m_CurrentSize += valueSize; - return true; - } - return false; - } - - public int CurrentSize => m_CurrentSize; - public IEnumerable OffsetValueDatas => m_BucketValueDatas; - } - List CreateBuckets() - { - List buckets = new(); - - foreach (var valueData in m_ValueDatas) - { - bool bucketFound = false; - foreach (var bucket in buckets) - { - if (bucket.TryAdd(valueData)) - { - bucketFound = true; - break; - } - } - if (bucketFound) - continue; - // Suitable bucket not found, create a new one - var newBucket = new Bucket(valueData); - buckets.Add(newBucket); - } - - return buckets; - } - public void ComputeOffsets() - { - m_ValueDataOffsets.Clear(); - m_BucketedValueDatas = CreateBuckets(); - int currentBucketOffset = 0; - foreach (var bucket in m_BucketedValueDatas) - { - foreach (var offsetValueData in bucket.OffsetValueDatas) - { - m_ValueDataOffsets[offsetValueData.ValueData] = currentBucketOffset + offsetValueData.OffsetInBucket; - } - currentBucketOffset += (bucket.CurrentSize + kAlignement - 1) / kAlignement * kAlignement; - } - m_TotalSize = currentBucketOffset; - } - - //TODO: Temporary method to get the sorted list of value datas - public List GetSortedValueDatas() - { - List sortedValueDatas = new(); - foreach (var bucket in m_BucketedValueDatas) - { - foreach (var offsetValueData in bucket.OffsetValueDatas) - { - sortedValueDatas.Add(offsetValueData.ValueData); - } - } - return sortedValueDatas; - } - - static int ValueSize(ValueData valueData) - { - return System.Runtime.InteropServices.Marshal.SizeOf(valueData.Type) / sizeof(uint); - } - } - - class StructuredDataLayoutContainer - { - Dictionary m_GraphValuesLayouts = new(); - - internal ValueBufferLayout CreateLayout(StructuredData structuredData) - { - if (!m_GraphValuesLayouts.TryGetValue(structuredData, out var layout)) - { - layout = new ValueBufferLayout(); - m_GraphValuesLayouts[structuredData] = layout; - } - - return layout; - } - - internal bool TryGetLayout(StructuredData structuredData, out ValueBufferLayout layout) - { - return m_GraphValuesLayouts.TryGetValue(structuredData, out layout); - } - } -} diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs index 143af1c00c1..05dae996af4 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs @@ -3,11 +3,12 @@ namespace Unity.GraphCommon.LowLevel.Editor { /// - /// Unordered data collection with elements of different types, referenced by any data identifier. + /// Ordered data collection with elements of different types, referenced by any data identifier. /// /*public*/ class StructuredData : IDataDescription { - Dictionary m_Datas = new(); + Dictionary m_DataIndirection = new(); + List m_Datas = new(); /// /// Adds a data element, providing the data identifier and the data description. @@ -17,24 +18,23 @@ namespace Unity.GraphCommon.LowLevel.Editor /// True if the data element was added, false otherwise (for instance, if it was already present). public bool AddSubdata(IDataKey dataKey, IDataDescription data) { - return m_Datas.TryAdd(dataKey, data); + bool added = m_DataIndirection.TryAdd(dataKey, m_Datas.Count); + if(added) + m_Datas.Add(data); + return added; } /// public IDataDescription GetSubdata(IDataKey dataKey) { - return m_Datas.GetValueOrDefault(dataKey); + if(m_DataIndirection.TryGetValue(dataKey, out int index)) + return m_Datas[index]; + return null; } /// - /// Enumerates all the subdata descriptions included in this data description. + /// Enumerates all the subdata descriptions included in this data description, in order of addition. /// - public IEnumerable SubDataDescriptions => m_Datas.Values; - - /// - /// Enumerates all the subdata descriptions included in this data description. - /// - public IEnumerable> SubDatas => m_Datas; + public IEnumerable SubDataDescriptions => m_Datas; } } - diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs.meta index fac2e97695e..0c05a05127d 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs.meta +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/StructuredData.cs.meta @@ -1,2 +1,3 @@ fileFormatVersion: 2 -guid: d420b861ffb8ecf469940460fcbae191 \ No newline at end of file +guid: fd343112d3bc41bb84bc2256d30c3086 +timeCreated: 1771943587 \ No newline at end of file diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs new file mode 100644 index 00000000000..c16736b3d18 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; + +namespace Unity.GraphCommon.LowLevel.Editor +{ + /// + /// Unordered data collection with elements of different types, referenced by any data identifier. + /// + /*public*/ class UnorderedData : IDataDescription + { + Dictionary m_Datas = new(); + + /// + /// Adds a data element, providing the data identifier and the data description. + /// + /// The data identifier for this element. + /// The data description for this element. + /// True if the data element was added, false otherwise (for instance, if it was already present). + public bool AddSubdata(IDataKey dataKey, IDataDescription data) + { + return m_Datas.TryAdd(dataKey, data); + } + + /// + public IDataDescription GetSubdata(IDataKey dataKey) + { + return m_Datas.GetValueOrDefault(dataKey); + } + + /// + /// Enumerates all the subdata descriptions included in this data description. + /// + public IEnumerable SubDataDescriptions => m_Datas.Values; + + /// + /// Enumerates all the subdata descriptions included in this data description. + /// + public IEnumerable> SubDatas => m_Datas; + + /// + public bool IsCompatible(IDataDescription other) + { + return other is StructuredData or UnorderedData; + } + } +} + diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs.meta new file mode 100644 index 00000000000..fac2e97695e --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d420b861ffb8ecf469940460fcbae191 \ No newline at end of file diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs index 56c2660e17e..6687721bfa0 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs @@ -15,8 +15,8 @@ public void WriteDescription(ShaderWriter shaderWriter, DataView dataView, Struc shaderWriter.WriteLine("VFXByteAddressBuffer buffer;"); shaderWriter.NewLine(); - var layoutCompilationData = context.data.Get(); - layoutCompilationData.TryGetLayout(structuredData, out var layout); + var layoutCompilationData = context.data.Get(); + layoutCompilationData.TryGetLayout(dataView.DataContainer.Id, out var layout); shaderWriter.WriteLine("void Init()"); shaderWriter.OpenBlock(); @@ -24,21 +24,22 @@ public void WriteDescription(ShaderWriter shaderWriter, DataView dataView, Struc shaderWriter.CloseBlock(); shaderWriter.NewLine(); - foreach (var subDataView in dataView.Children) + foreach (var subDataView in dataView.Flat) { - if (subDataView.DataDescription is not ValueData valueData) - continue; - var offset = layout.GetValueOffset(valueData); - var typeString = HlslCodeHelper.GetTypeName(valueData.Type); - var subDataName = subDataView.SubDataKey.ToString(); - DeclareMember(shaderWriter, typeString, subDataName, (uint)offset); + if (subDataView.DataDescription is ValueData valueData) + { + var offset = layout.GetValueOffset(valueData); + var typeString = HlslCodeHelper.GetTypeName(valueData.Type); + var subDataName = subDataView.SubDataKey.ToString(); + DeclareValueMember(shaderWriter, typeString, subDataName, (uint)offset); + } } shaderWriter.CloseBlock(false); shaderWriter.WriteLine(";", ShaderWriter.WriteLineOptions.NoIndent); } - void DeclareMember(ShaderWriter shaderWriter, string type, string name, uint offset) + void DeclareValueMember(ShaderWriter shaderWriter, string type, string name, uint offset) { shaderWriter.WriteLine($"{type} Load_{name}()"); shaderWriter.OpenBlock(); @@ -87,9 +88,20 @@ public bool WriteView(ShaderWriter shaderWriter, DataView usedDataView, DataView return true; } - public string GetSubdataName(IDataKey subDataKey) + public string GetSubdataName(DataView dataView, IDataKey subDataKey) + { + if (dataView.FindSubData(subDataKey, out var subDataView)) + { + if (subDataView.DataDescription is ValueData valueData) + return $".Load_{subDataKey}()"; + return string.Empty; + } + return null; + } + + public string GetSubdataTypeName(IDataKey subDataKey) { - return $".Load_{subDataKey}()"; + return string.Empty; } public void DefineResourceUsage(ShaderWriter shaderWriter, DataView usedDataView, DataView readDataView, diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs.meta index 821bafd0a65..2dfe0d591ec 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs.meta +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/DescriptionWriter/StructuredDataDescriptionWriter.cs.meta @@ -1,2 +1,3 @@ fileFormatVersion: 2 -guid: dd3b8b42a29da614f8419fc68a28eb4b \ No newline at end of file +guid: 1aa60eff29a947a8b41147641dac77de +timeCreated: 1772026669 \ No newline at end of file diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/IDataDescriptionWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/IDataDescriptionWriter.cs index e78a45a3c4e..8bf6db7cbdd 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/IDataDescriptionWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/IDataDescriptionWriter.cs @@ -10,7 +10,7 @@ interface IDataDescriptionWriter bool WriteView(ShaderWriter shaderWriter, DataView usedDataView, DataView readDataView, DataView writtenDataView, string name, string sourceName, CompilationContext context) => false; - string GetSubdataName(IDataKey subDataKey) => throw new System.NotImplementedException(); + string GetSubdataName(DataView dataView, IDataKey subDataKey) => throw new System.NotImplementedException(); string GetSubdataTypeName(IDataKey subDataKey) => throw new System.NotImplementedException(); diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Task/TemplatedTask.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Task/TemplatedTask.cs index 9cc6b140bd4..edaa0fc9eda 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Task/TemplatedTask.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Task/TemplatedTask.cs @@ -219,12 +219,18 @@ public TemplatedTaskBinding(System.Type dataType, BindingUsagePaths usagePaths) /// /// Unique data key that represents the graph values data used by this task. /// - public static UniqueDataKey GraphValuesKey { get; } = new UniqueDataKey("GraphValues"); + public static UniqueDataKey GraphValuesBufferKey { get; } = new UniqueDataKey("GraphValuesBuffer"); /// /// Unique data key that represents the (legacy) context data used by this task. /// public static UniqueDataKey ContextDataKey { get; } = new UniqueDataKey("ContextData"); + public static UniqueDataKey MaxParticleCountKey { get; } = new UniqueDataKey("maxParticleCount"); + public static UniqueDataKey SystemSeedKey { get; } = new UniqueDataKey("systemSeed"); + public static UniqueDataKey InitSpawnIndexKey { get; } = new UniqueDataKey("initSpawnIndex"); + public static DataPath MaxParticleCountPath => new(MaxParticleCountKey); + public static DataPath SystemSeedPath => new(SystemSeedKey); + public static DataPath InitSpawnIndexPath => new(InitSpawnIndexKey); /// /// Initializes a new instance of the class using the specified template name and arguments. /// diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Data/DescriptionWriter/ParticleSystemDataDescriptionWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Data/DescriptionWriter/ParticleSystemDataDescriptionWriter.cs index 951f84ecde3..f0cb2ed6315 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Data/DescriptionWriter/ParticleSystemDataDescriptionWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Data/DescriptionWriter/ParticleSystemDataDescriptionWriter.cs @@ -146,7 +146,7 @@ public bool WriteView(ShaderWriter shaderWriter, DataView usedDataView, DataView return true; } - public string GetSubdataName(IDataKey subDataKey) + public string GetSubdataName(DataView dataView, IDataKey subDataKey) { if (subDataKey == ParticleData.AttributeDataKey) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Passes/VfxGraphLegacyOutputPass.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Passes/VfxGraphLegacyOutputPass.cs index 75232447487..e746467cb18 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Passes/VfxGraphLegacyOutputPass.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Passes/VfxGraphLegacyOutputPass.cs @@ -220,24 +220,21 @@ void GenerateAttributeBufferDescriptions(ref CompilationContext context) void GenerateGraphValuesBufferDescriptions(ref CompilationContext context) { - var structuredDataLayoutContainer = context.data.Get(); + var dataLayoutContainer = context.data.Get(); - foreach (var dataView in context.graph.DataViews) + foreach (var dataContainer in context.graph.DataContainers) { - if (dataView.DataDescription is StructuredData structuredData) + if (dataLayoutContainer.TryGetLayout(dataContainer.Id, out var valueBufferLayout)) { - if (structuredDataLayoutContainer.TryGetLayout(structuredData, out var valueBufferLayout)) + uint bufferIndex = AddGPUBufferData(new VFXGPUBufferDesc() { - uint bufferIndex = AddGPUBufferData(new VFXGPUBufferDesc() - { - target = GraphicsBuffer.Target.Raw, - size = valueBufferLayout.GetBufferSize(), - stride = 4u, - mode = ComputeBufferMode.Dynamic, - }); + target = GraphicsBuffer.Target.Raw, + size = valueBufferLayout.GetBufferSize(), + stride = 4u, + mode = ComputeBufferMode.Dynamic, + }); - m_GpuBufferDescIndices[structuredData] = bufferIndex; - } + m_GpuBufferDescIndices[dataContainer.RootDataView.DataDescription] = bufferIndex; } } } @@ -433,10 +430,21 @@ bool GenerateParticleSystemDesc(ref CompilationContext context, VfxGraphLegacyPa VFXMapping[] GenerateSystemValuesMappings(CompilationContext context, VfxGraphLegacyParticleSystemContainer.ParticleSystem particleSystem) { var valueMappings = new List(); - var graphValueMappings = new Dictionary(); + var graphValueMappings = new List<(int, VFXMapping)>(); var taskNode = context.graph.TaskNodes[particleSystem.SystemTask.Id]; - ValueBufferLayout graphValueBufferLayout = new ValueBufferLayout(); + var dataLayoutContainer = context.data.Get(); + + DataContainerId graphValuesContainerId = DataContainerId.Invalid; + // Find graph values buffer in bindings + foreach (var dataBinding in taskNode.DataBindings) + { + if (dataBinding.BindingDataKey == TemplatedTask.GraphValuesBufferKey) + { + graphValuesContainerId = dataBinding.DataView.DataContainer.Id; + } + } + dataLayoutContainer.TryGetLayout(graphValuesContainerId, out var graphValuesBufferLayout); foreach (var dataBinding in taskNode.DataBindings) { @@ -449,9 +457,10 @@ VFXMapping[] GenerateSystemValuesMappings(CompilationContext context, VfxGraphLe valueMappings.Add(new VFXMapping(name, (int)index)); continue; } + // Graph values - graphValueMappings.Add(dataBinding.DataView.DataDescription as ValueData, new VFXMapping(name, (int)index)); - graphValueBufferLayout.AddValueData(dataBinding.DataView.DataDescription as ValueData); + int graphValueOffset = graphValuesBufferLayout.GetValueOffset(dataBinding.DataView.DataDescription as ValueData); + graphValueMappings.Add((graphValueOffset, new VFXMapping(name, (int)index))); } } List mappings = new(); @@ -462,13 +471,13 @@ VFXMapping[] GenerateSystemValuesMappings(CompilationContext context, VfxGraphLe mappings.Add(new VFXMapping("graphValuesOffset", valueMappings.Count + 1)); //Need to add the graph value mapping in the order of graph value layout for the runtime to work correctly - graphValueBufferLayout.ComputeOffsets(); - graphValueBufferLayout.GetSortedValueDatas(); - foreach (var valueData in graphValueBufferLayout.GetSortedValueDatas()) + graphValueMappings.Sort((a, b) => a.Item1.CompareTo(b.Item1)); + foreach ( (int _, VFXMapping mapping) in graphValueMappings) { - mappings.Add(graphValueMappings[valueData]); + mappings.Add(mapping); } return mappings.ToArray(); + } VFXMapping[] GenerateSystemBuffersMappings(CompilationContext context, VfxGraphLegacyParticleSystemContainer.ParticleSystem particleSystem) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs index 4f80c37f0ae..9f7bd178b57 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs @@ -25,7 +25,7 @@ public VfxGraphCompiler() m_GraphCompiler = new(new VfxGraphLegacyOutputPass(), new AttributeLayoutPass(), new VfxGraphLegacyParticleSystemPass(), - new StructuredDataLayoutPass(), + new DataLayoutPass(), new TemplateCodeGenerationPass(m_DataWriter)); } diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs index 80b85294f33..2f1867cac4b 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs @@ -26,12 +26,13 @@ public ParticleSystemBuildInfo(VFXData data) private static readonly IDataKey kParticleBindingKey = new NameDataKey("ParticleDataBinding"); private static readonly IDataKey kSpawnDataBindingKey = new NameDataKey("SpawnDataBinding"); private static readonly IDataKey kMainTextureKey = new NameDataKey("MainTexture"); + static readonly IDataKey kGraphValuesKey = new NameDataKey("GraphValues"); Dictionary m_ParticleSystems = new(); VFXSystemNames m_SystemNames = new(); VFXExpressionGraph m_ExpressionGraph; - Dictionary> m_StructuredDataNamesCount = new(); + Dictionary> m_GraphValueNameCounts = new(); public IReadOnlyGraph BuildGraph(VFXGraph graph) { @@ -100,7 +101,8 @@ public IReadOnlyGraph BuildGraph(VFXGraph graph) void Clear() { m_ParticleSystems.Clear(); - m_StructuredDataNamesCount.Clear(); + m_GraphValueNameCounts.Clear(); + m_SystemNames = new VFXSystemNames(); } void BuildSpawnerSystem(VFXBasicSpawner spawner, TaskGraph intermediateGraph) @@ -156,10 +158,10 @@ void BuildParticleSystem(ParticleSystemBuildInfo particleSystemBuildInfo, TaskGr var systemTask = intermediateGraph.AddTask(BuildSystemTask()); intermediateGraph.BindData(systemTask, kParticleBindingKey, particleData, BindingUsage.Write); - BuildGraphValuesBuffer(intermediateGraph, systemTask, out var graphValuesViewId, out var contextDataViewId, out var graphValuesBuffer); + BuildGraphValuesBuffer(intermediateGraph, systemTask, out var graphValuesBufferViewId, out var contextDataViewId, out var graphValuesBuffer); var initializeTask = intermediateGraph.AddTask(BuildInitializeTask(particleSystemBuildInfo.InitContext)); - BindExpressions(intermediateGraph, particleSystemBuildInfo.InitContext, initializeTask, systemTask, graphValuesBuffer, graphValuesViewId); + BindExpressions(intermediateGraph, particleSystemBuildInfo.InitContext, initializeTask, systemTask, graphValuesBuffer, graphValuesBufferViewId); BindContextData(intermediateGraph, initializeTask, contextDataViewId); var spawnData = particleSystemBuildInfo.InputSpawnData; @@ -173,7 +175,7 @@ void BuildParticleSystem(ParticleSystemBuildInfo particleSystemBuildInfo, TaskGr { var updateTask = intermediateGraph.AddTask(BuildUpdateTask(updateContext)); intermediateGraph.BindData(updateTask, kParticleBindingKey, particleData, BindingUsage.ReadWrite); - BindExpressions(intermediateGraph, updateContext, updateTask, systemTask, graphValuesBuffer, graphValuesViewId); + BindExpressions(intermediateGraph, updateContext, updateTask, systemTask, graphValuesBuffer, graphValuesBufferViewId); BindContextData(intermediateGraph, updateTask, contextDataViewId); } @@ -181,19 +183,34 @@ void BuildParticleSystem(ParticleSystemBuildInfo particleSystemBuildInfo, TaskGr { var outputTask = intermediateGraph.AddTask(BuildOutputTask(outputContext)); intermediateGraph.BindData(outputTask, kParticleBindingKey, particleData, BindingUsage.Read); - BindExpressions(intermediateGraph, outputContext, outputTask, systemTask, graphValuesBuffer, graphValuesViewId); + BindExpressions(intermediateGraph, outputContext, outputTask, systemTask, graphValuesBuffer, graphValuesBufferViewId); BindContextData(intermediateGraph, outputTask, contextDataViewId); } } - void BuildGraphValuesBuffer(TaskGraph intermediateGraph, TaskNodeId systemTask, out DataViewId graphValuesViewId, out DataViewId contextDataViewId, out StructuredData graphValuesBuffer) + void BuildGraphValuesBuffer(TaskGraph intermediateGraph, TaskNodeId systemTask, out DataViewId graphValuesBufferViewId, out DataViewId contextDataViewId, out StructuredData graphValuesBuffer) { graphValuesBuffer = new StructuredData(); - graphValuesViewId = intermediateGraph.AddData("GraphValuesBuffer", graphValuesBuffer); - intermediateGraph.BindData(systemTask, TemplatedTask.GraphValuesKey, graphValuesViewId, BindingUsage.Write); - graphValuesBuffer.AddSubdata(TemplatedTask.ContextDataKey, ValueData.Create(typeof(Vector4))); // Adds a default subdata for ContextData, which is expected from the C++ runtime. - contextDataViewId = intermediateGraph.GetSubdata(graphValuesViewId, TemplatedTask.ContextDataKey); - m_StructuredDataNamesCount.Add(graphValuesBuffer, new Dictionary()); + graphValuesBufferViewId = intermediateGraph.AddData("GraphValuesBuffer", graphValuesBuffer); + + StructuredData contextData = new StructuredData(); + contextData.AddSubdata(TemplatedTask.MaxParticleCountKey, ValueData.Create(typeof(uint))); + contextData.AddSubdata(TemplatedTask.SystemSeedKey, ValueData.Create(typeof(uint))); + contextData.AddSubdata(TemplatedTask.InitSpawnIndexKey, ValueData.Create(typeof(uint))); + NameDataKey paddingKey = new NameDataKey("padding"); + contextData.AddSubdata(paddingKey, ValueData.Create(typeof(uint))); + + graphValuesBuffer.AddSubdata(TemplatedTask.ContextDataKey, contextData); // Adds a default subdata for ContextData, which is expected from the C++ runtime. + + contextDataViewId = intermediateGraph.GetSubdata(graphValuesBufferViewId, TemplatedTask.ContextDataKey); + intermediateGraph.GetSubdata(contextDataViewId, paddingKey); // Force data view to be registered + + UnorderedData graphValues = new UnorderedData(); + graphValuesBuffer.AddSubdata(kGraphValuesKey, graphValues); + + intermediateGraph.BindData(systemTask, TemplatedTask.GraphValuesBufferKey, graphValuesBufferViewId, BindingUsage.Write); + + m_GraphValueNameCounts.Add(graphValuesBuffer, new Dictionary()); } void BindContextData(TaskGraph intermediateGraph, TaskNodeId contextTask, DataViewId contextDataViewId) @@ -219,8 +236,11 @@ void BindExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNodeId BindCPUExpressions(intermediateGraph, context, contextTask, systemTask); } - void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNodeId contextTask, TaskNodeId systemTask, StructuredData graphValuesBuffer, DataViewId graphValuesViewId) + void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNodeId contextTask, TaskNodeId systemTask, StructuredData graphValuesBuffer, DataViewId graphValuesBufferViewId) { + var graphValuesViewId = intermediateGraph.GetSubdata(graphValuesBufferViewId, kGraphValuesKey); + var graphValuesUnordered = intermediateGraph.DataViews[graphValuesViewId].DataDescription as UnorderedData; + var gpuMapper = m_ExpressionGraph.BuildGPUMapper(context); foreach (var expression in gpuMapper.expressions) { @@ -233,9 +253,12 @@ void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNod } else { - Debug.Assert(m_StructuredDataNamesCount.ContainsKey(graphValuesBuffer)); + if(expression.IsAny(VFXExpression.Flags.NotCompilableOnCPU)) + continue; + + Debug.Assert(m_GraphValueNameCounts.ContainsKey(graphValuesBuffer)); string bindingName = gpuMapper.GetData(expression)[0].name; - var nameCountMap = m_StructuredDataNamesCount[graphValuesBuffer]; + var nameCountMap = m_GraphValueNameCounts[graphValuesBuffer]; if (nameCountMap.TryGetValue(bindingName, out uint count)) { nameCountMap[bindingName] = count + 1; @@ -250,7 +273,8 @@ void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNod IDataKey systemBindingKey = new NameDataKey(systemUniqueBindingName); IDataKey contextBindingKey = new NameDataKey(gpuMapper.GetData(expression)[0].fullName); - if(graphValuesBuffer.AddSubdata(systemBindingKey, ValueData.Create(VFXExpression.TypeToType(expression.valueType)))) + var expressionValue = intermediateGraph.DataViews[expressionDataViewId].DataDescription; + if(graphValuesUnordered.AddSubdata(systemBindingKey, expressionValue)) { intermediateGraph.BindData(systemTask, systemBindingKey, expressionDataViewId, BindingUsage.Read); } @@ -287,7 +311,7 @@ ITask BuildSystemTask() new List() { new(kParticleBindingKey, DataPath.Empty), - new(TemplatedTask.GraphValuesKey, DataPath.Empty) + new(TemplatedTask.GraphValuesBufferKey, DataPath.Empty) }); } @@ -308,7 +332,9 @@ ITask BuildInitializeTask(VFXBasicInitialize initContext) spawnSystemUsage.Read.Add(new DataPath(SpawnData.SourceAttributeDataKey)); BindingUsagePaths contextDataUsage = new(); - contextDataUsage.Read.Add(DataPath.Empty); + contextDataUsage.Read.Add(TemplatedTask.MaxParticleCountPath); + contextDataUsage.Read.Add(TemplatedTask.SystemSeedPath); + contextDataUsage.Read.Add(TemplatedTask.InitSpawnIndexPath); var args = new TemplatedTaskArgs { @@ -341,7 +367,8 @@ ITask BuildUpdateTask(VFXBasicUpdate updateContext) particleSystemUsage.Write.Add(new DataPath(ParticleData.DeadlistKey)); BindingUsagePaths contextDataUsage = new(); - contextDataUsage.Read.Add(DataPath.Empty); + contextDataUsage.Read.Add(TemplatedTask.MaxParticleCountPath); + contextDataUsage.Read.Add(TemplatedTask.SystemSeedPath); TemplatedTaskArgs args = new TemplatedTaskArgs { diff --git a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Init.hlsl b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Init.hlsl index 2791f43e539..36ec8645e79 100644 --- a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Init.hlsl +++ b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Init.hlsl @@ -17,8 +17,8 @@ void main(ThreadData threadData) return; } - uint systemSeed = asuint(ContextData.y); - uint initSpawnIndex = asuint(ContextData.z); + uint systemSeed = ContextData.systemSeed; + uint initSpawnIndex = ContextData.initSpawnIndex; particleAttributes.particleId = initSpawnIndex + threadData.index; particleAttributes.seed = WangHash(particleAttributes.particleId ^ systemSeed); diff --git a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Update.hlsl b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Update.hlsl index 1a549294a44..8c451f18cee 100644 --- a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Update.hlsl +++ b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Templates/Update.hlsl @@ -6,7 +6,7 @@ void main(ThreadData threadData) { uint particleIndex = threadData.index; - uint maxParticleCount = asuint(ContextData.x); + uint maxParticleCount = ContextData.maxParticleCount; if(particleIndex >= maxParticleCount) { From 0998b2552c00fb221019f66cd4618e22f7401304 Mon Sep 17 00:00:00 2001 From: Justin Schwartz Date: Fri, 17 Apr 2026 07:18:53 +0000 Subject: [PATCH 08/56] Updated `HDAdditionalLightData` to work with CoreCLR --- .../Runtime/Debug/DebugLightVolumes.cs | 2 ++ .../Runtime/Lighting/Light/HDAdditionalLightData.cs | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugLightVolumes.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugLightVolumes.cs index 8eb3087fbd1..be62b3b7dc6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugLightVolumes.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugLightVolumes.cs @@ -108,6 +108,7 @@ public void RenderLightVolumes(RenderGraph renderGraph, LightingDebugSettings li mrt[0] = data.lightCountBuffer; mrt[1] = data.colorAccumulationBuffer; +#if UNITY_EDITOR if (data.lightOverlapEnabled) { // We only need the accumulation buffer, not the color (we only display the outline of the light shape in this mode). @@ -120,6 +121,7 @@ public void RenderLightVolumes(RenderGraph renderGraph, LightingDebugSettings li } } else +#endif { // Set the render target array CoreUtils.SetRenderTarget(natCmd, mrt, data.depthBuffer); 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 5282b75e333..0249ebe5c3e 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 @@ -138,9 +138,18 @@ public enum CelestialBodyShadingSource internal const float k_MinAreaLightShadowCone = 10.0f; internal const float k_MaxAreaLightShadowCone = 179.0f; +#if UNITY_EDITOR /// List of the lights that overlaps when the OverlapLight scene view mode is enabled internal static HashSet s_overlappingHDLights = new HashSet(); + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + s_overlappingHDLights?.Clear(); + s_overlappingHDLights = new HashSet(); + } +#endif + #region HDLight Properties API [ExcludeCopy] @@ -2193,7 +2202,9 @@ void OnDisable() } SetEmissiveMeshRendererEnabled(false); +#if UNITY_EDITOR s_overlappingHDLights.Remove(this); +#endif DestroyHDLightRenderEntity(); } From d6f04651f4a33e307eda37ce9262404394d96fdc Mon Sep 17 00:00:00 2001 From: Sebastien Phaneuf Date: Fri, 17 Apr 2026 07:19:04 +0000 Subject: [PATCH 09/56] Make HDRP Columndrawer more robust --- .../Editor/Lighting/HDLightingSearchColumnProviders.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs index 15cfc3d5bfc..1d8fe4e7b39 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs @@ -258,7 +258,7 @@ public static void ReflectionProbeResolutionSearchColumnProvider(SearchColumn co column.drawer = args => { var go = args.item.data as GameObject ?? args.item.ToObject(); - if (go == null || !go.TryGetComponent(out var hdProbe)) + if (go == null || !go.TryGetComponent(out var hdProbe) || args.value is not HDLightingSearchDataAccessors.ReflectionProbeResolutionData) { return args.value; } @@ -357,7 +357,7 @@ public static void ContactShadowsSearchColumnProvider(SearchColumn column) column.drawer = args => { var go = args.item.data as GameObject ?? args.item.ToObject(); - if (go == null || !go.TryGetComponent(out _)) + if (go == null || !go.TryGetComponent(out _) || args.value is not HDLightingSearchDataAccessors.ContactShadowsData) { return null; } @@ -420,7 +420,7 @@ public static void ShadowResolutionSearchColumnProvider(SearchColumn column) column.drawer = args => { var go = args.item.data as GameObject ?? args.item.ToObject(); - if (go == null || !go.TryGetComponent(out _)) + if (go == null || !go.TryGetComponent(out _) || args.value is not ShadowResolutionOption) { return null; } From 3c0ad4958e776bc92c5b35c4c8ef4902f0a090a8 Mon Sep 17 00:00:00 2001 From: Pema Malling Date: Fri, 17 Apr 2026 07:19:07 +0000 Subject: [PATCH 10/56] Higher threshold for AMD. --- .../Assets/Tests/LightBaker/InputExtractionMaterials.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tests/SRPTests/Projects/HDRP_Tests/Assets/Tests/LightBaker/InputExtractionMaterials.cs b/Tests/SRPTests/Projects/HDRP_Tests/Assets/Tests/LightBaker/InputExtractionMaterials.cs index 722c3883fc1..f06bd7d5d5e 100644 --- a/Tests/SRPTests/Projects/HDRP_Tests/Assets/Tests/LightBaker/InputExtractionMaterials.cs +++ b/Tests/SRPTests/Projects/HDRP_Tests/Assets/Tests/LightBaker/InputExtractionMaterials.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NUnit.Framework; using UnityEditor.SceneManagement; @@ -233,6 +234,11 @@ public void MetaPassTemplateTests( } Texture2D actualTexture2D = ConvertVector4ImageToRGBAHalfTexture(actualTextureData.resolution.width, actualTextureData.resolution.height, actualTextureData.data); + // Tests need higher threshold on AMD due to platform-specific rasterization differences. + bool isAMD = SystemInfo.graphicsDeviceVendor.Contains("amd", StringComparison.InvariantCultureIgnoreCase) || + SystemInfo.graphicsDeviceVendor.Contains("ati", StringComparison.InvariantCultureIgnoreCase); +float rmseThreshold = isAMD ? Math.Max(0.02f, metaPassTest.RMSEThreshold) : metaPassTest.RMSEThreshold; + ImageComparisonSettings imageComparisonSettings = new() { @@ -242,7 +248,7 @@ public void MetaPassTemplateTests( ActiveImageTests = ImageComparisonSettings.ImageTests.RMSE, IncorrectPixelsThreshold = 1.0f / (actualTexture2D.width * actualTexture2D.height), - RMSEThreshold = metaPassTest.RMSEThreshold + RMSEThreshold = rmseThreshold, }; ImageAssert.AreEqualLinearHDR( From 00b0523ebe7d42464956b7bfcc714d18c97ad2fa Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 17 Apr 2026 07:19:08 +0000 Subject: [PATCH 11/56] GFXLIGHT-2009 : Adding environment intensity into Surface Cache. --- .../Runtime/Lighting/SurfaceCache/Estimation.hlsl | 4 +++- .../Runtime/Lighting/SurfaceCache/PathTracing.hlsl | 5 +++-- .../Runtime/Lighting/SurfaceCache/SurfaceCache.cs | 4 ++++ .../Lighting/SurfaceCache/SurfaceCacheWorld.cs | 11 +++++++++++ .../SurfaceCacheGIRendererFeature.cs | 5 ++++- .../SurfaceCacheWorldAdapter.cs | 5 ++++- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl index 3db3f7400a5..4d08b80dab7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl @@ -48,6 +48,7 @@ uint _RingConfigOffset; float3 _VolumeTargetPos; float _MaterialAtlasTexelSize; // The size of 1 texel in the atlases above float _AlbedoBoost; +float _EnvironmentIntensityMultiplier; uint _PunctualLightSampleCount; float3 _DirectionalLightDirection; float3 _DirectionalLightIntensity; @@ -175,7 +176,7 @@ void SampleEnvironmentAndDirectionalBounceAndMultiBounceRadiance( for(uint sampleIdx = 0; sampleIdx < _SampleCount; ++sampleIdx) { ray.direction = UniformHemisphereSample(rng.GetSample(0), patchGeo.normal); - const float3 radiance = IncomingEnviromentAndDirectionalBounceAndMultiBounceRadiance( + const float3 radiance = IncomingEnvironmentAndDirectionalBounceAndMultiBounceRadiance( dispatchInfo, accelStruct, ray, @@ -184,6 +185,7 @@ void SampleEnvironmentAndDirectionalBounceAndMultiBounceRadiance( _DirectionalLightIntensity, _MultiBounce, _EnvironmentCubemap, + _EnvironmentIntensityMultiplier, sampler_EnvironmentCubemap, _PatchIrradiances, patchGeometries, diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl index 75c6c6cba64..1ef666b2113 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl @@ -268,7 +268,7 @@ float3 OutgoingDirectionalBounceAndMultiBounceRadiance( return radiance; } -float3 IncomingEnviromentAndDirectionalBounceAndMultiBounceRadiance( +float3 IncomingEnvironmentAndDirectionalBounceAndMultiBounceRadiance( UnifiedRT::DispatchInfo dispatchInfo, UnifiedRT::RayTracingAccelStruct accelStruct, UnifiedRT::Ray ray, @@ -277,6 +277,7 @@ float3 IncomingEnviromentAndDirectionalBounceAndMultiBounceRadiance( float3 dirLightIntensity, bool multiBounce, TextureCube envTex, + float envIntensityMultiplier, SamplerState envSampler, PatchIrradianceBufferType patchIrradiances, PatchGeometryBufferType patchGeometries, @@ -348,7 +349,7 @@ float3 IncomingEnviromentAndDirectionalBounceAndMultiBounceRadiance( } else { - radiance = envTex.SampleLevel(envSampler, ray.direction, 0); + radiance = envIntensityMultiplier * envTex.SampleLevel(envSampler, ray.direction, 0); } return radiance; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs index df9147b5d7c..c758db1325d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs @@ -346,6 +346,7 @@ private class EstimationPassData internal uint PunctualLightSampleCount; internal SurfaceCacheWorld World; internal float AlbedoBoost; + internal float EnvironmentIntensityMultiplier; internal uint FrameIdx; internal uint CascadeCount; internal bool MultiBounce; @@ -404,6 +405,7 @@ internal static class ShaderIDs public static readonly int _MaterialEntries = Shader.PropertyToID("_MaterialEntries"); public static readonly int _AlbedoTextures = Shader.PropertyToID("_AlbedoTextures"); public static readonly int _AlbedoBoost = Shader.PropertyToID("_AlbedoBoost"); + public static readonly int _EnvironmentIntensityMultiplier = Shader.PropertyToID("_EnvironmentIntensityMultiplier"); public static readonly int _DirectionalLightDirection = Shader.PropertyToID("_DirectionalLightDirection"); public static readonly int _DirectionalLightIntensity = Shader.PropertyToID("_DirectionalLightIntensity"); public static readonly int _MaterialAtlasTexelSize = Shader.PropertyToID("_MaterialAtlasTexelSize"); @@ -624,6 +626,7 @@ private void RecordEstimation(RenderGraph renderGraph, uint frameIdx, SurfaceCac passData.VolumeTargetPos = Volume.TargetPos; passData.FrameIdx = frameIdx; passData.AlbedoBoost = _albedoBoost; + passData.EnvironmentIntensityMultiplier = world.GetEnvironmentIntensityMultiplier(); passData.VolumeSpatialResolution = Volume.SpatialResolution; passData.CascadeOffsets = Volume.CascadeOffsetBuffer; passData.CascadeCount = Volume.CascadeCount; @@ -732,6 +735,7 @@ static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) shader.SetTextureParam(cmd, ShaderIDs._AlbedoTextures, data.World.GetMaterialAlbedoTextures()); shader.SetTextureParam(cmd, ShaderIDs._EmissionTextures, data.World.GetMaterialEmissionTextures()); shader.SetFloatParam(cmd, ShaderIDs._AlbedoBoost, data.AlbedoBoost); + shader.SetFloatParam(cmd, ShaderIDs._EnvironmentIntensityMultiplier, data.EnvironmentIntensityMultiplier); shader.SetFloatParam(cmd, ShaderIDs._MaterialAtlasTexelSize, GetMaterialAtlasTexelSize(data.World.GetMaterialAlbedoTextures())); shader.SetIntParam(cmd, ShaderIDs._PunctualLightCount, punctualLightCount); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs index 782167060eb..0729668bdb2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs @@ -306,6 +306,7 @@ public void Dispose() private MaterialPool _materialPool; private AccelStructAdapter _rayTracingAccelerationStructure; private CubemapRender _cubemapRender; + private float _environmentIntensityMultiplier = 1.0f; public void Init(RayTracingContext ctx, WorldResourceSet worldResources) { @@ -350,6 +351,16 @@ public void SetEnvironmentColor(Color color) _cubemapRender.SetColor(color); } + public void SetEnvironmentIntensityMultiplier(float multiplier) + { + _environmentIntensityMultiplier = multiplier; + } + + public float GetEnvironmentIntensityMultiplier() + { + return _environmentIntensityMultiplier; + } + public ComputeBuffer GetMaterialListBuffer() { return _materialPool.MaterialBuffer; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs index 068a2dad0a7..1a3140df198 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs @@ -658,7 +658,10 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer builder.SetRenderFunc((PatchAllocationPassData data, ComputeGraphContext cgContext) => AllocatePatches(data, cgContext)); } - _worldAdapter.Update(_sceneTracker, RenderSettings.ambientMode, RenderSettings.skybox, RenderSettings.ambientSkyColor, _world); + // RenderSettings.ambientIntensity is used directly as a linear value for Surface Cache, which is not currently + // the case for the standard ambient probe lighting, which is assumed to be in gamma space and then converted to + // linear space. We will make this more coherent for the ambient probe in the future. + _worldAdapter.Update(_sceneTracker, RenderSettings.ambientMode, RenderSettings.skybox, RenderSettings.ambientSkyColor, RenderSettings.ambientIntensity, _world); using (var builder = renderGraph.AddUnsafePass("Surface Cache World Update", out WorldUpdatePassData passData)) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs index 987122257d2..6d0736c20cf 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs @@ -54,7 +54,7 @@ public SurfaceCacheWorldAdapter(SurfaceCacheWorld world, Material fallbackMateri _entityIDToWorldMaterialDescriptors.Add(fallbackMaterial.GetEntityId(), _fallbackMaterialDescriptor); } - internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, Material skyboxMaterial, Color ambientSkycolor, SurfaceCacheWorld world) + internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, Material skyboxMaterial, Color ambientSkycolor, float envIntensityMultiplier, SurfaceCacheWorld world) { const bool filterBakedLights = true; var changes = sceneTracker.GetChanges(filterBakedLights); @@ -83,16 +83,19 @@ internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, { world.SetEnvironmentMode(CubemapRender.Mode.Material); world.SetEnvironmentMaterial(skyboxMaterial); + world.SetEnvironmentIntensityMultiplier(envIntensityMultiplier); } else if (ambientMode == AmbientMode.Flat) { world.SetEnvironmentMode(CubemapRender.Mode.Color); world.SetEnvironmentColor(ambientSkycolor); + world.SetEnvironmentIntensityMultiplier(1.0f); } else { world.SetEnvironmentMode(CubemapRender.Mode.Color); world.SetEnvironmentColor(Color.black); + world.SetEnvironmentIntensityMultiplier(1.0f); } } From 41a9e074877fb38caf842c1e5a5f7e8d3a3ea224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Carr=C3=A8re?= Date: Sun, 19 Apr 2026 23:59:04 +0000 Subject: [PATCH 12/56] =?UTF-8?q?docg-8491:=20LOD=20Group=20Animate=20Cros?= =?UTF-8?q?s-fading=20is=20unsupported=20by=20GPU=20Resid=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Documentation~/make-object-compatible-gpu-rendering.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/make-object-compatible-gpu-rendering.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/make-object-compatible-gpu-rendering.md index 4e90a838362..25fb9bc778d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/make-object-compatible-gpu-rendering.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/make-object-compatible-gpu-rendering.md @@ -6,6 +6,7 @@ To make a GameObject compatible with the [GPU Resident Drawer](gpu-resident-draw - In the Mesh Renderer component, **Light Probes** isn't set to **Use Proxy Volume**. - Uses only static global illumination, not real time global illumination. - Uses a shader that supports DOTS instancing. Refer to [Supporting DOTS Instancing](https://docs.unity3d.com/Manual/dots-instancing-shaders.html) for more information. +- In the LOD Group component, **Animate Cross-fading** is disabled. - Doesn't move position after one camera finishes rendering and before another camera starts rendering. - Doesn't use the `MaterialPropertyBlock` API. - Doesn't have a script that uses a per-instance callback, for example `OnRenderObject`. From d771a551383d0c49f3dd9415b4a7f2cfd9329a86 Mon Sep 17 00:00:00 2001 From: Kenny Tan Date: Mon, 20 Apr 2026 19:04:44 +0000 Subject: [PATCH 13/56] [UUM-138310][6000.6][2D] Ensure Universal.2D.Runtime supports Fast Enter Play Mode --- .../Runtime/2D/Lights/Light2DManager.cs | 11 +++- .../Runtime/2D/Passes/Utility/LayerUtility.cs | 40 ++++++------ .../2D/Passes/Utility/Light2DLookupTexture.cs | 57 ++++++++--------- .../Runtime/2D/Passes/Utility/LightBatch.cs | 15 +++-- .../2D/Passes/Utility/RendererLighting.cs | 11 ++++ .../ScriptableRenderPass2D.cs | 10 ++- .../Rendergraph/CopyCameraSortingLayerPass.cs | 11 ++-- .../Runtime/2D/Rendergraph/DrawLight2DPass.cs | 8 +++ .../2D/Rendergraph/Renderer2DRendergraph.cs | 25 ++++++-- .../Runtime/2D/Rendergraph/UpscalePass.cs | 34 +++-------- .../Shadow Provider Utility/EdgeDictionary.cs | 8 +++ .../Shadow Provider Utility/ShadowUtility.cs | 13 +++- .../VertexDictionary.cs | 11 +++- .../2D/Shadows/ShadowCasterGroup2DManager.cs | 12 ++-- .../030_InjectionRenderPass2D.asset | 61 ++++++++++++++++--- .../CustomRendererFeature2D.cs | 2 + .../Assets/Test/Runtime/Renderer2DTests.cs | 1 - 17 files changed, 213 insertions(+), 117 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DManager.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DManager.cs index 44d120fcbd7..ee35249b332 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DManager.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DManager.cs @@ -6,7 +6,16 @@ internal static class Light2DManager { private static SortingLayer[] s_SortingLayers; - public static List lights { get; } = new List(); + internal static List lights { get; } = new List(); + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void ResetStaticsOnLoad() + { + s_SortingLayers = null; + lights.Clear(); + } +#endif internal static void Initialize() { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs index 496461d8c5d..18025277703 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs @@ -6,30 +6,23 @@ namespace UnityEngine.Rendering.Universal internal class LayerBatch { #if UNITY_EDITOR - public int startIndex; - public int endIndex; + internal int startIndex; + internal int endIndex; #endif - public int startLayerID; - public int endLayerValue; - public SortingLayerRange layerRange; - public LightStats lightStats; - public bool useNormals; + internal int startLayerID; + internal int endLayerValue; + internal SortingLayerRange layerRange; + internal LightStats lightStats; + internal bool useNormals; - public List lights; - public List shadowIndices; - public List shadowCasters; + internal List lights = new List(); + internal List shadowIndices = new List(); + internal List shadowCasters = new List(); internal int[] activeBlendStylesIndices; - public void InitRTIds(int index) - { - lights = new List(); - shadowIndices = new List(); - shadowCasters = new List(); - } - // This range check uses SortingLayer.value. - internal bool IsValueWithinLayerRange(int value) + internal bool IsValueWithinLayerRange(int value) { return value >= layerRange.lowerBound && value <= layerRange.upperBound; } @@ -39,6 +32,14 @@ internal static class LayerUtility { private static LayerBatch[] s_LayerBatches; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + s_LayerBatches = null; + } +#endif + private static bool CanBatchLightsInLayer(int layerIndex1, int layerIndex2, SortingLayer[] sortingLayers, ILight2DCullResult lightCullResult) { var layerId1 = sortingLayers[layerIndex1].id; @@ -114,10 +115,7 @@ private static void InitializeBatchInfos(SortingLayer[] cachedSortingLayers) if (needInit) { for (var i = 0; i < s_LayerBatches.Length; i++) - { s_LayerBatches[i] = new LayerBatch(); - s_LayerBatches[i].InitRTIds(i); - } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/Light2DLookupTexture.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/Light2DLookupTexture.cs index 6d80e1d0a22..e074c6e855e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/Light2DLookupTexture.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/Light2DLookupTexture.cs @@ -9,58 +9,49 @@ internal static class Light2DLookupTexture internal static readonly int k_LightLookupID = Shader.PropertyToID(k_LightLookupProperty); internal static readonly int k_FalloffLookupID = Shader.PropertyToID(k_FalloffLookupProperty); - private static Texture2D s_PointLightLookupTexture; - private static Texture2D s_FalloffLookupTexture; - private static RTHandle m_LightLookupRTHandle = null; - private static RTHandle m_FalloffRTHandle = null; + private static RTHandle s_LightLookupRTHandle = null; + private static RTHandle s_FalloffRTHandle = null; + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + Release(); + } +#endif public static RTHandle GetLightLookupTexture_Rendergraph() { - if (s_PointLightLookupTexture == null || m_LightLookupRTHandle == null) + if (s_LightLookupRTHandle == null || s_LightLookupRTHandle?.externalTexture == null) { - var lightLookupTexture = GetLightLookupTexture(); + var lightLookupTexture = CreatePointLightLookupTexture(); - m_LightLookupRTHandle?.Release(); - m_LightLookupRTHandle = RTHandles.Alloc(lightLookupTexture); + s_LightLookupRTHandle?.Release(); + s_LightLookupRTHandle = RTHandles.Alloc(lightLookupTexture); } - return m_LightLookupRTHandle; + return s_LightLookupRTHandle; } public static RTHandle GetFallOffLookupTexture_Rendergraph() { - if (s_FalloffLookupTexture == null || m_FalloffRTHandle == null) + if (s_FalloffRTHandle == null || s_FalloffRTHandle?.externalTexture == null) { - var fallOffLookupTexture = GetFalloffLookupTexture(); + var fallOffLookupTexture = CreateFalloffLookupTexture(); - m_FalloffRTHandle?.Release(); - m_FalloffRTHandle = RTHandles.Alloc(fallOffLookupTexture); + s_FalloffRTHandle?.Release(); + s_FalloffRTHandle = RTHandles.Alloc(fallOffLookupTexture); } - return m_FalloffRTHandle; + return s_FalloffRTHandle; } public static void Release() { - m_FalloffRTHandle?.Release(); - m_LightLookupRTHandle?.Release(); - m_FalloffRTHandle = null; - m_LightLookupRTHandle = null; - } - - public static Texture GetLightLookupTexture() - { - if (s_PointLightLookupTexture == null) - s_PointLightLookupTexture = CreatePointLightLookupTexture(); - return s_PointLightLookupTexture; - } - - public static Texture GetFalloffLookupTexture() - { - if (s_FalloffLookupTexture == null) - s_FalloffLookupTexture = CreateFalloffLookupTexture(); - return s_FalloffLookupTexture; - + s_FalloffRTHandle?.Release(); + s_LightLookupRTHandle?.Release(); + s_FalloffRTHandle = null; + s_LightLookupRTHandle = null; } private static Texture2D CreatePointLightLookupTexture() diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LightBatch.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LightBatch.cs index 327cabefe5d..c141af5f6f5 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LightBatch.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LightBatch.cs @@ -60,7 +60,6 @@ internal void Reset() // identified from the Blue Channel of the Vertex Colors (Solely used for this purpose). This can batch a maximum of kLightMod meshes in best-case scenario. Simple but no optizations have been added yet internal class LightBatch { - static readonly ProfilingSampler profilingDrawBatched = new ProfilingSampler("Light2D Batcher"); static readonly int k_BufferOffset = Shader.PropertyToID("_BatchBufferOffset"); static int sBatchIndexCounter = 0; // For LightMesh asset conditioning to facilitate batching. @@ -83,6 +82,14 @@ internal class LightBatch private int batchCount = 0; private int activeCount = 0; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + sBatchIndexCounter = 0; + } +#endif + internal NativeArray nativeBuffer { get @@ -150,15 +157,15 @@ void Validate() { #if UNITY_EDITOR if (!kRegisterCallback) - UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += OnAssemblyReload; + UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += Release; kRegisterCallback = true; #endif } - void OnAssemblyReload() + internal void Release() { for (int i = 0; i < LightBuffer.kCount; ++i) - lightBuffer[activeCount].Release(); + lightBuffer[i]?.Release(); } void ResetInternals() diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs index 321f03a60ff..b62602ca66b 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs @@ -78,6 +78,17 @@ internal static class RendererLighting // Light Batcher. internal static LightBatch lightBatch = new LightBatch(); +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + s_HasSetupRenderTextureFormatToUse = false; + s_RenderTextureFormatToUse = GraphicsFormat.R8G8B8A8_UNorm; + lightBatch.Release(); + lightBatch = new LightBatch(); + } +#endif + internal static GraphicsFormat GetRenderTextureFormat() { if (!s_HasSetupRenderTextureFormatToUse) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/RendererFeatures/ScriptableRenderPass2D.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/RendererFeatures/ScriptableRenderPass2D.cs index 0d3a6a12c02..9820ff03586 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/RendererFeatures/ScriptableRenderPass2D.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/RendererFeatures/ScriptableRenderPass2D.cs @@ -1,4 +1,3 @@ - using System; namespace UnityEngine.Rendering.Universal @@ -85,9 +84,16 @@ internal static class RenderPassEvents2DEnumValues // We cache the values in this array at construction time to avoid runtime allocations, which we would cause if we accessed valuesInternal directly. public static int[] values; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod()] + static void ResetStaticsOnLoad() + { + } +#endif + static RenderPassEvents2DEnumValues() { - System.Array valuesInternal = Enum.GetValues(typeof(RenderPassEvent2D)); + Array valuesInternal = Enum.GetValues(typeof(RenderPassEvent2D)); values = new int[valuesInternal.Length]; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/CopyCameraSortingLayerPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/CopyCameraSortingLayerPass.cs index 3a596ec74e9..0135bdcb7fc 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/CopyCameraSortingLayerPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/CopyCameraSortingLayerPass.cs @@ -1,4 +1,3 @@ -using System; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; @@ -12,7 +11,7 @@ internal class CopyCameraSortingLayerPass : ScriptableRenderPass private static readonly ProfilingSampler m_ExecuteProfilingSampler = new ProfilingSampler("Copy"); internal static readonly string k_CameraSortingLayerTexture = "_CameraSortingLayerTexture"; internal static readonly int k_CameraSortingLayerTextureId = Shader.PropertyToID(k_CameraSortingLayerTexture); - static Material m_BlitMaterial; + Material m_BlitMaterial; public CopyCameraSortingLayerPass(Material blitMaterial) { @@ -37,18 +36,19 @@ public static void ConfigureDescriptor(Downsampling downsamplingMethod, ref Rend filterMode = downsamplingMethod == Downsampling.None || downsamplingMethod == Downsampling._4xBox ? FilterMode.Point : FilterMode.Bilinear; } - private static void Execute(RasterCommandBuffer cmd, RTHandle source) + private static void Execute(RasterCommandBuffer cmd, RTHandle source, Material blitMaterial) { using (new ProfilingScope(cmd, m_ExecuteProfilingSampler)) { Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one; - Blitter.BlitTexture(cmd, source, viewportScale, m_BlitMaterial, source.rt.filterMode == FilterMode.Bilinear ? 1 : 0); + Blitter.BlitTexture(cmd, source, viewportScale, blitMaterial, source.rt.filterMode == FilterMode.Bilinear ? 1 : 0); } } class PassData { internal TextureHandle source; + internal Material blitMaterial; } public void Render(RenderGraph graph, ContextContainer frameData) @@ -59,6 +59,7 @@ public void Render(RenderGraph graph, ContextContainer frameData) using (var builder = graph.AddRasterRenderPass(k_CopyCameraSortingLayerPass, out var passData, m_ProfilingSampler)) { passData.source = commonResourceData.activeColorTexture; + passData.blitMaterial = m_BlitMaterial; builder.SetRenderAttachment(universal2DResourceData.cameraSortingLayerTexture, 0); builder.UseTexture(passData.source); @@ -66,7 +67,7 @@ public void Render(RenderGraph graph, ContextContainer frameData) builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { - Execute(context.cmd, data.source); + Execute(context.cmd, data.source, data.blitMaterial); }); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs index 8a2b1de03f6..a5add8656b9 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs @@ -21,6 +21,14 @@ internal class DrawLight2DPass : ScriptableRenderPass internal static MaterialPropertyBlock s_PropertyBlock = new MaterialPropertyBlock(); +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + s_PropertyBlock = new MaterialPropertyBlock(); + } +#endif + internal void Setup(RenderGraph renderGraph, ref Renderer2DData rendererData) { foreach (var light in rendererData.lightCullResult.visibleLights) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs index ee9bbd216a3..81990b91d56 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs @@ -30,8 +30,8 @@ private struct ImportResourceSummary // TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we should remove all RTHandles and use per frame RG textures. // We use 2 camera color handles so we can handle the edge case when a pass might want to read and write the same target. // This is not allowed so we just swap the current target, this keeps camera stacking working and avoids an extra blit pass. - static int m_CurrentColorHandle = 0; - internal RTHandle[] m_RenderGraphCameraColorHandles = new RTHandle[] + private static int m_CurrentColorHandle = 0; + private static RTHandle[] m_RenderGraphCameraColorHandles = new RTHandle[] { null, null }; @@ -71,6 +71,24 @@ private struct ImportResourceSummary PostProcess m_PostProcess; ColorGradingLutPass m_ColorGradingLutPassRenderGraph; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + m_CurrentColorHandle = 0; + + m_RenderGraphCameraColorHandles[0]?.Release(); + m_RenderGraphCameraColorHandles[1]?.Release(); + m_RenderGraphCameraColorHandles = new RTHandle[] + { + null, null + }; + + m_OffscreenUIColorHandle?.Release(); + m_OffscreenUIColorHandle = null; + } +#endif + private RTHandle currentRenderGraphCameraColorHandle { get @@ -482,7 +500,6 @@ void CreateResources(RenderGraph renderGraph) cameraData.baseCamera.TryGetComponent(out var baseCameraData); var baseRenderer = (Renderer2D)baseCameraData.scriptableRenderer; - m_RenderGraphCameraColorHandles = baseRenderer.m_RenderGraphCameraColorHandles; m_RenderGraphCameraDepthHandle = baseRenderer.m_RenderGraphCameraDepthHandle; m_RenderGraphBackbufferColorHandle = baseRenderer.m_RenderGraphBackbufferColorHandle; m_RenderGraphBackbufferDepthHandle = baseRenderer.m_RenderGraphBackbufferDepthHandle; @@ -1045,7 +1062,6 @@ protected override void Dispose(bool disposing) private void CleanupRenderGraphResources() { m_Renderer2DData.Dispose(); - m_UpscalePass.Dispose(); m_CopyDepthPass?.Dispose(); m_FinalBlitPass?.Dispose(); m_OffscreenUICoverPrepass?.Dispose(); @@ -1060,6 +1076,7 @@ private void CleanupRenderGraphResources() m_RenderGraphBackbufferColorHandle?.Release(); m_RenderGraphBackbufferDepthHandle?.Release(); m_CameraSortingLayerHandle?.Release(); + m_OffscreenUIColorHandle?.Release(); Light2DManager.Dispose(); Light2DLookupTexture.Release(); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/UpscalePass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/UpscalePass.cs index e45564211b2..83f82966679 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/UpscalePass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/UpscalePass.cs @@ -1,5 +1,3 @@ -using System; -using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal @@ -10,14 +8,12 @@ internal class UpscalePass : ScriptableRenderPass private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler(k_UpscalePass); private static readonly ProfilingSampler m_ExecuteProfilingSampler = new ProfilingSampler("Draw Upscale"); - static Material m_BlitMaterial; - - private RTHandle source; - private RTHandle destination; + Material m_BlitMaterial; private class PassData { internal TextureHandle source; + internal Material blitMaterial; } public UpscalePass(RenderPassEvent evt, Material blitMaterial) @@ -26,30 +22,12 @@ public UpscalePass(RenderPassEvent evt, Material blitMaterial) m_BlitMaterial = blitMaterial; } - public void Setup(RTHandle colorTargetHandle, int width, int height, FilterMode mode, RenderTextureDescriptor cameraTargetDescriptor, out RTHandle upscaleHandle) - { - source = colorTargetHandle; - - RenderTextureDescriptor desc = cameraTargetDescriptor; - desc.width = width; - desc.height = height; - desc.depthStencilFormat = GraphicsFormat.None; - RenderingUtils.ReAllocateHandleIfNeeded(ref destination, desc, mode, TextureWrapMode.Clamp, name: "_UpscaleTexture"); - - upscaleHandle = destination; - } - - public void Dispose() - { - destination?.Release(); - } - - private static void ExecutePass(RasterCommandBuffer cmd, RTHandle source) + private static void ExecutePass(RasterCommandBuffer cmd, RTHandle source, Material blitMaterial) { using (new ProfilingScope(cmd, m_ExecuteProfilingSampler)) { Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one; - Blitter.BlitTexture(cmd, source, viewportScale, m_BlitMaterial, source.rt.filterMode == FilterMode.Bilinear ? 1 : 0); + Blitter.BlitTexture(cmd, source, viewportScale, blitMaterial, source.rt.filterMode == FilterMode.Bilinear ? 1 : 0); } } @@ -62,6 +40,8 @@ public void Render(RenderGraph graph, Camera camera, in TextureHandle cameraColo using (var builder = graph.AddRasterRenderPass(k_UpscalePass, out var passData, m_ProfilingSampler)) { passData.source = cameraColorAttachment; + passData.blitMaterial = m_BlitMaterial; + builder.SetRenderAttachment(upscaleHandle, 0); builder.UseTexture(cameraColorAttachment); @@ -69,7 +49,7 @@ public void Render(RenderGraph graph, Camera camera, in TextureHandle cameraColo builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { - ExecutePass(context.cmd, data.source); + ExecutePass(context.cmd, data.source, data.blitMaterial); }); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/EdgeDictionary.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/EdgeDictionary.cs index 8b7896de1e1..6f95fbdf76e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/EdgeDictionary.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/EdgeDictionary.cs @@ -9,6 +9,14 @@ internal struct EdgeDictionary : IEdgeStore { static private Dictionary m_EdgeDictionary = new Dictionary(new EdgeComparer()); // This is done so we don't create garbage allocating and deallocating a dictionary object +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + m_EdgeDictionary.Clear(); + } +#endif + private class EdgeComparer : IEqualityComparer { public bool Equals(ShadowEdge edge0, ShadowEdge edge1) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/ShadowUtility.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/ShadowUtility.cs index c2c0173be0d..fde2029da4c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/ShadowUtility.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/ShadowUtility.cs @@ -1,8 +1,6 @@ using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Unity.Collections; -using System.Collections.Generic; using UnityEngine.U2D; using Unity.Collections.LowLevel.Unsafe; using Unity.Mathematics; @@ -75,6 +73,17 @@ public void Initialize() new VertexAttributeDescriptor(VertexAttribute.Tangent, VertexAttributeFormat.Float32, 4), }; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + m_VertexLayout = new VertexAttributeDescriptor[] + { + new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3), + new VertexAttributeDescriptor(VertexAttribute.Tangent, VertexAttributeFormat.Float32, 4), + }; + } +#endif unsafe static int GetNextShapeStart(int currentShape, int* inShapeStartingEdgePtr, int inShapeStartingEdgeLength, int maxValue) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/VertexDictionary.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/VertexDictionary.cs index afe0f356fbc..04d657f595d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/VertexDictionary.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/Shadow Provider Utility/VertexDictionary.cs @@ -1,12 +1,19 @@ using System.Collections.Generic; -using UnityEngine; using Unity.Collections; - +using UnityEngine; internal struct VertexDictionary { static Dictionary m_VertexDictionary = new Dictionary(); +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod] + static void ResetStaticsOnLoad() + { + m_VertexDictionary.Clear(); + } +#endif + public NativeArray GetIndexRemap(NativeArray vertices, NativeArray indices) { // Create a mapping to unique vertices diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCasterGroup2DManager.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCasterGroup2DManager.cs index 994e7066d27..2c26667c9df 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCasterGroup2DManager.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCasterGroup2DManager.cs @@ -1,7 +1,4 @@ -using System.Collections; using System.Collections.Generic; -using UnityEngine; - #if UNITY_EDITOR using UnityEditor; #endif @@ -17,10 +14,13 @@ internal class ShadowCasterGroup2DManager public static List shadowCasterGroups { get { return s_ShadowCasterGroups; } } - #if UNITY_EDITOR - static ShadowCasterGroup2DManager() + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void ResetStaticsOnLoad() { + s_ShadowCasterGroups = null; + + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; // Probably not needed, but added just in case this might get registered again EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } @@ -29,7 +29,6 @@ private static void OnPlayModeStateChanged(PlayModeStateChange state) if (s_ShadowCasterGroups != null && (state == PlayModeStateChange.ExitingEditMode || state == PlayModeStateChange.ExitingPlayMode)) s_ShadowCasterGroups.Clear(); } - #endif public static void CacheValues() @@ -81,7 +80,6 @@ static CompositeShadowCaster2D FindTopMostCompositeShadowCaster(ShadowCaster2D s return retGroup; } - public static int GetRendereringPriority(ShadowCaster2D shadowCaster) { int sortingOrder = 0; diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/030_InjectionRenderPass2D.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/030_InjectionRenderPass2D.asset index 27e50be62ed..c302af8ee03 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/030_InjectionRenderPass2D.asset +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/030_InjectionRenderPass2D.asset @@ -1,5 +1,50 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!114 &-3911986160458590877 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ca7c3d2ecbc6d7b4c917e1e525696db0, type: 3} + m_Name: AfterShadowsRendererFeature2D + m_EditorClassIdentifier: Universal2DGraphicsTests::UnityEngine.Rendering.Universal.CustomRendererFeature2D + m_Active: 1 + injectionPoint2D: 400 + sortingLayerID: 0 +--- !u!114 &-1673627150717267422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ca7c3d2ecbc6d7b4c917e1e525696db0, type: 3} + m_Name: BeforeNormalsRendererFeature2D + m_EditorClassIdentifier: Universal2DGraphicsTests::UnityEngine.Rendering.Universal.CustomRendererFeature2D + m_Active: 1 + injectionPoint2D: 100 + sortingLayerID: -538112021 +--- !u!114 &-675228469949227643 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ca7c3d2ecbc6d7b4c917e1e525696db0, type: 3} + m_Name: BeforeLightsRendererFeature2D + m_EditorClassIdentifier: Universal2DGraphicsTests::UnityEngine.Rendering.Universal.CustomRendererFeature2D + m_Active: 1 + injectionPoint2D: 500 + sortingLayerID: 116359401 --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 @@ -13,11 +58,9 @@ MonoBehaviour: m_Name: 030_InjectionRenderPass2D m_EditorClassIdentifier: Unity.RenderPipelines.Universal.2D.Runtime::UnityEngine.Rendering.Universal.Renderer2DData debugShaders: - debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, - type: 3} + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} - probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, - type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} probeVolumeResources: probeVolumeDebugShader: {fileID: 0} probeVolumeFragmentationDebugShader: {fileID: 0} @@ -26,8 +69,11 @@ MonoBehaviour: probeSamplingDebugMesh: {fileID: 0} probeSamplingDebugTexture: {fileID: 0} probeVolumeBlendStatesCS: {fileID: 0} - m_RendererFeatures: [] - m_RendererFeatureMap: + m_RendererFeatures: + - {fileID: -1673627150717267422} + - {fileID: -3911986160458590877} + - {fileID: -675228469949227643} + m_RendererFeatureMap: 22520c43f914c6e863159f4b50d5b5c9851d72ba481ba1f6 m_LayerMask: serializedVersion: 2 m_Bits: 4294967295 @@ -56,5 +102,4 @@ MonoBehaviour: m_MaxShadowRenderTextureCount: 1 m_PostProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} m_DefaultMaterialType: 0 - m_DefaultCustomMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, - type: 2} + m_DefaultCustomMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/CustomRendererFeature2D.cs b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/CustomRendererFeature2D.cs index d8e77309e07..05a3612b4b9 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/CustomRendererFeature2D.cs +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/030_RenderPass2D/CustomRendererFeature2D.cs @@ -14,6 +14,8 @@ public override void Create() renderPassEvent2D = injectionPoint2D, renderPassSortingLayerID = sortingLayerID }; + + m_CustomRenderPass2D.ConfigureInput(ScriptableRenderPassInput.Color); } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs index 36df44c638f..3a37ad68433 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs @@ -95,7 +95,6 @@ public void OverlayRendererUsesRenderTexturesFromBase() Renderer2D baseRenderer = m_BaseCameraData.scriptableRenderer as Renderer2D; Renderer2D overlayRenderer = m_OverlayCameraData.scriptableRenderer as Renderer2D; - Assert.AreEqual(baseRenderer.m_RenderGraphCameraColorHandles, overlayRenderer.m_RenderGraphCameraColorHandles); Assert.AreEqual(baseRenderer.m_RenderGraphCameraDepthHandle, overlayRenderer.m_RenderGraphCameraDepthHandle); } From 670b262e2fb4fb91861e254dc96ade8765062a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Chapelain?= Date: Tue, 21 Apr 2026 00:55:54 +0000 Subject: [PATCH 14/56] [SRP] Fix missing meshes in SRP scene templates --- .../Editor/SceneTemplates/HDRPBasicScenePipeline.cs | 13 +++++++++++++ .../Editor/SceneTemplates/URPBasicScenePipeline.cs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/SceneTemplates/HDRPBasicScenePipeline.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/SceneTemplates/HDRPBasicScenePipeline.cs index cbb8ceb9c32..67ded4bedbe 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/SceneTemplates/HDRPBasicScenePipeline.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/SceneTemplates/HDRPBasicScenePipeline.cs @@ -14,6 +14,19 @@ void ISceneTemplatePipeline.AfterTemplateInstantiation(SceneTemplateAsset sceneT //To avoid problematic behavior and warnings in the future, let's remove all missing scripts monobehaviors. foreach (GameObject go in Resources.FindObjectsOfTypeAll()) GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go); + + foreach (var go in scene.GetRootGameObjects()) + { + foreach (var meshFilter in go.GetComponentsInChildren(true)) + { + if (meshFilter.sharedMesh != null) + { + var mesh = meshFilter.sharedMesh; + meshFilter.sharedMesh = null; + meshFilter.sharedMesh = mesh; + } + } + } } void ISceneTemplatePipeline.BeforeTemplateInstantiation(SceneTemplateAsset sceneTemplateAsset, bool isAdditive, string sceneName) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/SceneTemplates/URPBasicScenePipeline.cs b/Packages/com.unity.render-pipelines.universal/Editor/SceneTemplates/URPBasicScenePipeline.cs index 8de69cb4bf7..534707d00cf 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/SceneTemplates/URPBasicScenePipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/SceneTemplates/URPBasicScenePipeline.cs @@ -14,6 +14,19 @@ void ISceneTemplatePipeline.AfterTemplateInstantiation(SceneTemplateAsset sceneT //To avoid problematic behavior and warnings in the future, let's remove all missing scripts monobehaviors. foreach (GameObject go in Resources.FindObjectsOfTypeAll()) GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go); + + foreach (var go in scene.GetRootGameObjects()) + { + foreach (var meshFilter in go.GetComponentsInChildren(true)) + { + if (meshFilter.sharedMesh != null) + { + var mesh = meshFilter.sharedMesh; + meshFilter.sharedMesh = null; + meshFilter.sharedMesh = mesh; + } + } + } } void ISceneTemplatePipeline.BeforeTemplateInstantiation(SceneTemplateAsset sceneTemplateAsset, bool isAdditive, string sceneName) From 1d0b116b49583c8e5912ad02fc9a66b232bfe6c8 Mon Sep 17 00:00:00 2001 From: Rasmus Roenn Nielsen Date: Tue, 21 Apr 2026 00:56:06 +0000 Subject: [PATCH 15/56] Surface Cache: Deferred Bounce Patch Allocation --- .../Lighting/SurfaceCache/Estimation.hlsl | 60 ++--- .../SurfaceCache/PatchAllocation.compute | 73 ++++++ .../SurfaceCache/PatchAllocation.compute.meta | 3 + .../SurfaceCache/PatchAllocationRequest.hlsl | 12 + .../PatchAllocationRequest.hlsl.meta | 3 + .../Lighting/SurfaceCache/PatchUtil.hlsl | 50 ---- .../Lighting/SurfaceCache/PathTracing.hlsl | 28 +-- .../Lighting/SurfaceCache/Scrolling.compute | 12 +- .../SurfaceCache/SpatialFiltering.compute | 12 +- .../Lighting/SurfaceCache/SurfaceCache.cs | 215 ++++++++++++++---- .../SurfaceCacheRenderPipelineResources.cs | 9 + .../Debug.compute | 10 +- .../PatchAllocation.compute | 10 +- .../ScreenResolveLookup.compute | 12 +- .../SurfaceCacheGIRendererFeature.cs | 16 +- 15 files changed, 345 insertions(+), 180 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl.meta diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl index 4d08b80dab7..ade66c135d7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Estimation.hlsl @@ -1,30 +1,23 @@ #define PATCH_UTIL_USE_RW_PATCH_IRRADIANCE_BUFFER -#if BOUNCE_PATCH_ALLOCATION -#define PATCH_UTIL_USE_RW_PATCH_GEOMETRY_BUFFER -#define PATCH_UTIL_USE_RW_CELL_PATCH_INDEX_BUFFER -#define PATCH_UTIL_USE_RW_PATCH_CELL_INDEX_BUFFER -#define PATCH_UTIL_USE_RW_CELL_ALLOCATION_MARK_BUFFER -#define RING_BUFFER_USE_RW_RING_CONFIG_BUFFER -#endif - #include "Common.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Sampling/QuasiRandom.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/Common.hlsl" #include "PathTracing.hlsl" +#include "PatchAllocationRequest.hlsl" #include "RingBuffer.hlsl" #include "PatchUtil.hlsl" #include "TemporalFiltering.hlsl" #include "PunctualLights.hlsl" RWStructuredBuffer _PatchIrradiances; -RWStructuredBuffer _PatchStatistics; -RingConfigBufferType _RingConfigBuffer; -PatchGeometryBufferType _PatchGeometries; -CellPatchIndexBufferType _CellPatchIndices; -PatchCellIndexBufferType _PatchCellIndices; -CellAllocationMarkBufferType _CellAllocationMarks; -StructuredBuffer _CascadeOffsets; +RWStructuredBuffer _PatchStatistics; +RWStructuredBuffer _PatchAllocationRequests; +RWStructuredBuffer _PatchAllocationRequestCount; +StructuredBuffer _RingConfigBuffer; +StructuredBuffer _PatchGeometries; +StructuredBuffer _CellPatchIndices; +StructuredBuffer _VolumeCascadeOffsets; StructuredBuffer _MaterialEntries; StructuredBuffer _PunctualLightSamples; StructuredBuffer _PunctualLights; @@ -39,7 +32,7 @@ UNIFIED_RT_DECLARE_ACCEL_STRUCT(_RayTracingAccelerationStructure); uint _PunctualLightCount; uint _FrameIdx; uint _VolumeSpatialResolution; -uint _CascadeCount; +uint _VolumeCascadeCount; float _VolumeVoxelMinSize; uint _MultiBounce; uint _SampleCount; @@ -52,6 +45,7 @@ float _EnvironmentIntensityMultiplier; uint _PunctualLightSampleCount; float3 _DirectionalLightDirection; float3 _DirectionalLightIntensity; +uint _BouncePatchAllocation; void ProcessAndStoreRadianceSample(RWStructuredBuffer patchIrradiances, RWStructuredBuffer patchStatistics, uint patchIdx, SphericalHarmonics::RGBL1 radianceSample, float shortHysteresis) { @@ -157,16 +151,14 @@ void SampleEnvironmentAndDirectionalBounceAndMultiBounceRadiance( UnifiedRT::DispatchInfo dispatchInfo, MaterialPoolParamSet matPoolParams, PatchUtil::PatchGeometry patchGeo, - float volumeVoxelMinSize, - PatchGeometryBufferType patchGeometries, RWStructuredBuffer patchStatistics, - PatchUtil::PatchAllocationParamSet allocParams, + CellPatchIndexBufferType cellPatchIndices, PatchUtil::VolumeParamSet volumeParams, inout SphericalHarmonics::RGBL1 accumulator, inout bool gotValidSamples) { UnifiedRT::Ray ray; - ray.origin = OffsetRayOrigin(patchGeo.position, patchGeo.normal, GetAdditionalRayOffset(volumeVoxelMinSize)); + ray.origin = OffsetRayOrigin(patchGeo.position, patchGeo.normal, GetAdditionalRayOffset(volumeParams.voxelMinSize)); ray.tMin = 0; ray.tMax = FLT_MAX; @@ -188,9 +180,10 @@ void SampleEnvironmentAndDirectionalBounceAndMultiBounceRadiance( _EnvironmentIntensityMultiplier, sampler_EnvironmentCubemap, _PatchIrradiances, - patchGeometries, patchStatistics, - allocParams, + _PatchAllocationRequests, + _PatchAllocationRequestCount, + cellPatchIndices, volumeParams, enablePatchAllocation, frameIndex); @@ -224,7 +217,11 @@ void Estimate(UnifiedRT::DispatchInfo dispatchInfo) QrngKronecker2D rng; const PatchUtil::PatchGeometry patchGeo = _PatchGeometries[patchIdx]; - bool enablePatchAllocation = (PatchUtil::GetRank(_PatchStatistics[patchIdx].counters) == 0); + bool enablePatchAllocation; + if (_BouncePatchAllocation) + enablePatchAllocation = (PatchUtil::GetRank(_PatchStatistics[patchIdx].counters) == 0); + else + enablePatchAllocation = false; MaterialPoolParamSet matPoolParams; matPoolParams.materialEntries = _MaterialEntries; @@ -239,15 +236,8 @@ void Estimate(UnifiedRT::DispatchInfo dispatchInfo) volumeParams.spatialResolution = _VolumeSpatialResolution; volumeParams.voxelMinSize = _VolumeVoxelMinSize; volumeParams.targetPos = _VolumeTargetPos; - volumeParams.cascadeOffsets = _CascadeOffsets; - volumeParams.cascadeCount = _CascadeCount; - - PatchUtil::PatchAllocationParamSet allocParams; - allocParams.cellPatchIndices = _CellPatchIndices; - allocParams.patchCellIndices = _PatchCellIndices; - allocParams.cellAllocationMarks = _CellAllocationMarks; - allocParams.ringConfigBuffer = _RingConfigBuffer; - allocParams.ringConfigOffset = _RingConfigOffset; + volumeParams.cascadeOffsets = _VolumeCascadeOffsets; + volumeParams.cascadeCount = _VolumeCascadeCount; SphericalHarmonics::RGBL1 radianceSampleMean = (SphericalHarmonics::RGBL1)0; bool gotValidSamples = false; @@ -264,10 +254,8 @@ void Estimate(UnifiedRT::DispatchInfo dispatchInfo) dispatchInfo, matPoolParams, patchGeo, - _VolumeVoxelMinSize, - _PatchGeometries, _PatchStatistics, - allocParams, + _CellPatchIndices, volumeParams, radianceSampleMean, gotValidSamples); @@ -291,5 +279,3 @@ void Estimate(UnifiedRT::DispatchInfo dispatchInfo) if (gotValidSamples) ProcessAndStoreRadianceSample(_PatchIrradiances, _PatchStatistics, patchIdx, radianceSampleMean, _ShortHysteresis); } - - diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute new file mode 100644 index 00000000000..b1d7c2e53e7 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute @@ -0,0 +1,73 @@ +#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal glcore ps5 +#pragma kernel Allocate + +#include "PatchAllocationRequest.hlsl" +#include "Common.hlsl" +#include "PatchUtil.hlsl" + +RWStructuredBuffer _PatchIrradiances0; +RWStructuredBuffer _PatchIrradiances1; +RWStructuredBuffer _PatchGeometries; +RWStructuredBuffer _PatchStatistics; +RWStructuredBuffer _PatchCellIndices; +RWStructuredBuffer _CellPatchIndices; +RWStructuredBuffer _CellAllocationMarks; +RWStructuredBuffer _RingConfigBuffer; + +StructuredBuffer _Requests; +StructuredBuffer _RequestCount; +StructuredBuffer _VolumeCascadeOffsets; + +uint _RingConfigOffset; +uint _VolumeSpatialResolution; +uint _VolumeCascadeCount; +float _VolumeVoxelMinSize; +float3 _VolumeTargetPos; +uint _FrameIndex; + +[numthreads(256, 1, 1)] +void Allocate(uint threadIdx : SV_DispatchThreadID) +{ + const uint requestCount = _RequestCount[0]; + + if (threadIdx < PatchAllocationRequestMax && threadIdx < requestCount) + { + PatchUtil::VolumeParamSet volumeParams; + volumeParams.spatialResolution = _VolumeSpatialResolution; + volumeParams.voxelMinSize = _VolumeVoxelMinSize; + volumeParams.targetPos = _VolumeTargetPos; + volumeParams.cascadeOffsets = _VolumeCascadeOffsets; + volumeParams.cascadeCount = _VolumeCascadeCount; + + const PatchAllocationRequest req = _Requests[threadIdx]; + + PatchUtil::VolumePositionResolution patchPosResolution = PatchUtil::ResolveVolumePosition(req.position, volumeParams); + if (!patchPosResolution.isValid()) + return; + + const uint directionIdx = PatchUtil::GetDirectionIndex(req.normal, PatchUtil::volumeAngularResolution); + const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(patchPosResolution.positionVolumeSpace, volumeParams.spatialResolution, volumeParams.cascadeOffsets[patchPosResolution.cascadeIdx]); + const uint cellIdx = PatchUtil::GetCellIndex(patchPosResolution.cascadeIdx, positionStorageSpace, directionIdx, volumeParams.spatialResolution, PatchUtil::volumeAngularResolution); + + PatchUtil::PatchIndexResolutionResult resolutionResult = PatchUtil::ResolvePatchIndex( + _RingConfigBuffer, + _RingConfigOffset, + _CellPatchIndices, + _PatchCellIndices, + _CellAllocationMarks, + cellIdx); + + if (resolutionResult.code == PatchUtil::patchIndexResolutionCodeAllocationSuccess) + { + PatchUtil::PatchGeometry geo; + geo.position = req.position; + geo.normal = req.normal; + _PatchGeometries[resolutionResult.patchIdx] = geo; + + SphericalHarmonics::RGBL1 irradianceSeed = (SphericalHarmonics::RGBL1)0; + _PatchIrradiances0[resolutionResult.patchIdx] = irradianceSeed; + _PatchIrradiances1[resolutionResult.patchIdx] = irradianceSeed; + _PatchStatistics[resolutionResult.patchIdx] = PatchUtil::InitPatchStatistics(irradianceSeed.l0, _FrameIndex, /*rank*/ 1); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute.meta b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute.meta new file mode 100644 index 00000000000..b5656c93021 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocation.compute.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b271ec1ddd8048458fa529e8e7cfe960 +timeCreated: 1776242564 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl new file mode 100644 index 00000000000..d4dd28fac6f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl @@ -0,0 +1,12 @@ +#ifndef SURFACE_CACHE_PATCH_ALLOCATION_REQUEST +#define SURFACE_CACHE_PATCH_ALLOCATION_REQUEST + +struct PatchAllocationRequest +{ + float3 position; + float3 normal; +}; + +static const uint PatchAllocationRequestMax = 1024; + +#endif diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl.meta new file mode 100644 index 00000000000..7e66c294437 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchAllocationRequest.hlsl.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7ed0dbab70f0403298ce88263059d1d1 +timeCreated: 1776245090 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchUtil.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchUtil.hlsl index 60dace7845e..057d7aef6d0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchUtil.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PatchUtil.hlsl @@ -76,15 +76,6 @@ namespace PatchUtil uint cascadeCount; }; - struct PatchAllocationParamSet - { - CellPatchIndexBufferType cellPatchIndices; - PatchCellIndexBufferType patchCellIndices; - CellAllocationMarkBufferType cellAllocationMarks; - RingConfigBufferType ringConfigBuffer; - uint ringConfigOffset; - }; - uint ModuloDistance(uint a, uint b, uint modulo) { int dif = abs(int(a) - int(b)); @@ -465,47 +456,6 @@ namespace PatchUtil return stats; } - -#if BOUNCE_PATCH_ALLOCATION - void AllocatePatch( - float3 worldPosition, - float3 worldNormal, - RWStructuredBuffer patchIrradiances, - RWStructuredBuffer patchGeometries, - RWStructuredBuffer patchStatistics, - PatchAllocationParamSet allocParams, - PatchUtil::VolumeParamSet volumeParams, - uint frameIndex) - { - PatchUtil::VolumePositionResolution patchPosResolution = PatchUtil::ResolveVolumePosition(worldPosition, volumeParams); - if (!patchPosResolution.isValid()) - return; - - const uint directionIdx = PatchUtil::GetDirectionIndex(worldNormal, PatchUtil::volumeAngularResolution); - const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(patchPosResolution.positionVolumeSpace, volumeParams.spatialResolution, volumeParams.cascadeOffsets[patchPosResolution.cascadeIdx]); - const uint cellIdx = PatchUtil::GetCellIndex(patchPosResolution.cascadeIdx, positionStorageSpace, directionIdx, volumeParams.spatialResolution, PatchUtil::volumeAngularResolution); - - PatchUtil::PatchIndexResolutionResult resolutionResult = PatchUtil::ResolvePatchIndex( - allocParams.ringConfigBuffer, - allocParams.ringConfigOffset, - allocParams.cellPatchIndices, - allocParams.patchCellIndices, - allocParams.cellAllocationMarks, - cellIdx); - - if (resolutionResult.code == PatchUtil::patchIndexResolutionCodeAllocationSuccess) - { - PatchUtil::PatchGeometry geo; - geo.position = worldPosition; - geo.normal = worldNormal; - patchGeometries[resolutionResult.patchIdx] = geo; - - SphericalHarmonics::RGBL1 irradianceSeed = (SphericalHarmonics::RGBL1)0; - patchIrradiances[resolutionResult.patchIdx] = irradianceSeed; - patchStatistics[resolutionResult.patchIdx] = PatchUtil::InitPatchStatistics(irradianceSeed.l0, frameIndex, /*rank*/ 1); - } - } -#endif } #endif diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl index 1ef666b2113..b3f842c6830 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/PathTracing.hlsl @@ -7,6 +7,7 @@ #include "Packages/com.unity.render-pipelines.core/Runtime/PathTracing/MaterialPool/MaterialPool.hlsl" #include "Common.hlsl" #include "PatchUtil.hlsl" +#include "PatchAllocationRequest.hlsl" #include "PunctualLights.hlsl" struct SurfaceGeometry @@ -280,9 +281,10 @@ float3 IncomingEnvironmentAndDirectionalBounceAndMultiBounceRadiance( float envIntensityMultiplier, SamplerState envSampler, PatchIrradianceBufferType patchIrradiances, - PatchGeometryBufferType patchGeometries, RWStructuredBuffer patchStatistics, - PatchUtil::PatchAllocationParamSet allocParams, + RWStructuredBuffer allocationRequests, + RWStructuredBuffer allocationRequestCount, + CellPatchIndexBufferType cellPatchIndices, PatchUtil::VolumeParamSet volumeParams, bool enablePatchAllocation, uint frameIndex) @@ -313,26 +315,25 @@ float3 IncomingEnvironmentAndDirectionalBounceAndMultiBounceRadiance( dirLightIntensity, multiBounce, patchIrradiances, - allocParams.cellPatchIndices, + cellPatchIndices, volumeParams, hitAlbedo, hitEmission, bouncePatchIndex); - #if BOUNCE_PATCH_ALLOCATION if (enablePatchAllocation) { if (bouncePatchIndex == PatchUtil::invalidPatchIndex) { - PatchUtil::AllocatePatch( - hitGeo.position, - hitGeo.normal, - patchIrradiances, - patchGeometries, - patchStatistics, - allocParams, - volumeParams, - frameIndex); + uint requestIdx; + InterlockedAdd(allocationRequestCount[0], 1, requestIdx); + if (requestIdx < PatchAllocationRequestMax) + { + PatchAllocationRequest req; + req.position = hitGeo.position; + req.normal = hitGeo.normal; + allocationRequests[requestIdx] = req; + } } else { @@ -344,7 +345,6 @@ float3 IncomingEnvironmentAndDirectionalBounceAndMultiBounceRadiance( } } } - #endif } } else diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Scrolling.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Scrolling.compute index 28e07984625..d59a3013ed2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Scrolling.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/Scrolling.compute @@ -10,23 +10,23 @@ RWStructuredBuffer _CellAllocationMarks; RWStructuredBuffer _CellPatchIndices; RWStructuredBuffer _PatchCellIndices; -StructuredBuffer _NewCascadeOffsets; +StructuredBuffer _NewVolumeCascadeOffsets; -int4 _OldCascadeOffsets[cascadeMax]; +int4 _OldVolumeCascadeOffsets[cascadeMax]; uint _VolumeSpatialResolution; -uint _CascadeCount; +uint _VolumeCascadeCount; [numthreads(8, 8, 8)] void Scroll(uint3 threadId : SV_DispatchThreadID) { - if (any(uint3(_VolumeSpatialResolution, _VolumeSpatialResolution, _VolumeSpatialResolution * _CascadeCount) <= threadId)) + if (any(uint3(_VolumeSpatialResolution, _VolumeSpatialResolution, _VolumeSpatialResolution * _VolumeCascadeCount) <= threadId)) return; const uint3 positionStorageSpace = threadId % _VolumeSpatialResolution; const uint cascadeIdx = threadId.z / _VolumeSpatialResolution; - const int3 newCascadeOffset = _NewCascadeOffsets[cascadeIdx]; - const int3 oldCascadeOffset = _OldCascadeOffsets[cascadeIdx].xyz; + const int3 newCascadeOffset = _NewVolumeCascadeOffsets[cascadeIdx]; + const int3 oldCascadeOffset = _OldVolumeCascadeOffsets[cascadeIdx].xyz; const int3 positionStorageSpaceInt = int3(positionStorageSpace); const int3 oldPositionVolumeSpace = PatchUtil::ConvertStorageSpaceToVolumeSpace(positionStorageSpaceInt, _VolumeSpatialResolution, oldCascadeOffset); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SpatialFiltering.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SpatialFiltering.compute index 1dd20cdf0ba..1082fbb08fb 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SpatialFiltering.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SpatialFiltering.compute @@ -12,11 +12,11 @@ StructuredBuffer _InputPatchIrradiances; StructuredBuffer _PatchGeometries; RWStructuredBuffer _OutputPatchIrradiances; StructuredBuffer _CellPatchIndices; -StructuredBuffer _CascadeOffsets; +StructuredBuffer _VolumeCascadeOffsets; uint _FrameIdx; float _VolumeVoxelMinSize; -uint _CascadeCount; +uint _VolumeCascadeCount; uint _VolumeSpatialResolution; uint _SampleCount; uint _RingConfigOffset; @@ -41,15 +41,15 @@ void FilterSpatially(uint patchIdx : SV_DispatchThreadID) float3 right; OrthoBasisFromVector(patchGeo.normal, up, right); - const int cascadeResolution = PatchUtil::ResolveCascadeIndex(_VolumeTargetPos, patchGeo.position, _VolumeSpatialResolution, _CascadeCount, _VolumeVoxelMinSize); - const uint cascadeIdx = cascadeResolution != -1 ? cascadeResolution : _CascadeCount - 1; + const int cascadeResolution = PatchUtil::ResolveCascadeIndex(_VolumeTargetPos, patchGeo.position, _VolumeSpatialResolution, _VolumeCascadeCount, _VolumeVoxelMinSize); + const uint cascadeIdx = cascadeResolution != -1 ? cascadeResolution : _VolumeCascadeCount - 1; PatchUtil::VolumeParamSet volume; volume.targetPos = _VolumeTargetPos; volume.spatialResolution = _VolumeSpatialResolution; volume.voxelMinSize = _VolumeVoxelMinSize; - volume.cascadeOffsets = _CascadeOffsets; - volume.cascadeCount = _CascadeCount; + volume.cascadeOffsets = _VolumeCascadeOffsets; + volume.cascadeCount = _VolumeCascadeCount; for (uint sampleIdx = 0; sampleIdx < _SampleCount; ++sampleIdx) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs index c758db1325d..7997b25dbb2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCache.cs @@ -50,6 +50,30 @@ public void Dispose() } } + internal class SurfaceCachePatchAllocationRequestList : IDisposable + { + const int _requestStride = sizeof(float) * 6; + public const int RequestMax = 1024; + + GraphicsBuffer _requests; + GraphicsBuffer _count; + + public SurfaceCachePatchAllocationRequestList() + { + _requests = new GraphicsBuffer(GraphicsBuffer.Target.Structured, RequestMax, _requestStride); + _count = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 1, 4); + } + + public GraphicsBuffer Requests => _requests; + public GraphicsBuffer Count => _count; + + public void Dispose() + { + _requests.Dispose(); + _count.Dispose(); + } + } + internal class SurfaceCachePatchList : IDisposable { private readonly uint _capacity; @@ -177,6 +201,10 @@ internal class SurfaceCacheResourceSet internal int EvictionKernel; internal uint3 EvictionKernelGroupSize; + internal ComputeShader PatchAllocationShader; + internal int PatchAllocationKernel; + internal uint3 PatchAllocationKernelGroupSize; + internal ComputeShader DefragShader; internal int DefragKernel; internal uint3 DefragKernelGroupSize; @@ -184,7 +212,6 @@ internal class SurfaceCacheResourceSet internal IRayTracingShader PunctualLightSamplingShader; internal IRayTracingShader EstimationShader; - internal LocalKeyword EstimationBounceAllocKeyword; internal ComputeShader SpatialFilteringShader; internal int SpatialFilteringKernel; @@ -215,6 +242,10 @@ internal bool LoadFromRenderPipelineResources(RayTracingContext rtContext) EvictionKernel = EvictionShader.FindKernel("Evict"); EvictionShader.GetKernelThreadGroupSizes(EvictionKernel, out EvictionKernelGroupSize.x, out EvictionKernelGroupSize.y, out EvictionKernelGroupSize.z); + PatchAllocationShader = rpResources.patchAllocationShader; + PatchAllocationKernel = PatchAllocationShader.FindKernel("Allocate"); + PatchAllocationShader.GetKernelThreadGroupSizes(PatchAllocationKernel, out PatchAllocationKernelGroupSize.x, out PatchAllocationKernelGroupSize.y, out PatchAllocationKernelGroupSize.z); + SpatialFilteringShader = rpResources.spatialFilteringShader; SpatialFilteringKernel = SpatialFilteringShader.FindKernel("FilterSpatially"); SpatialFilteringShader.GetKernelThreadGroupSizes(SpatialFilteringKernel, out SpatialFilteringKernelGroupSize.x, out SpatialFilteringKernelGroupSize.y, out SpatialFilteringKernelGroupSize.z); @@ -247,7 +278,6 @@ internal bool LoadFromRenderPipelineResources(RayTracingContext rtContext) PunctualLightSamplingShader = rtContext.CreateRayTracingShader(punctualLightSamplingUnifiedObj); EstimationShader = rtContext.CreateRayTracingShader(estimationUnifiedObj); - EstimationBounceAllocKeyword = EstimationShader.CreateLocalKeyword("BOUNCE_PATCH_ALLOCATION"); return true; } @@ -259,10 +289,12 @@ internal class SurfaceCache : IDisposable private readonly GraphicsBuffer _punctualLightSamples; private readonly SurfaceCachePatchList _patches; + private readonly SurfaceCachePatchAllocationRequestList _patchAllocationRequests; private readonly SurfaceCacheVolume _volume; private readonly SurfaceCacheRingConfig _ringConfig; private readonly SurfaceCacheResourceSet _resources; private GraphicsBuffer _traceScratch; + uint[] _zero = new uint[] { 0 }; private SurfaceCacheEstimationParameterSet _estimationParams; private SurfaceCachePatchFilteringParameterSet _patchFilteringParams; @@ -285,11 +317,11 @@ private class ScrollingPassData internal GraphicsBuffer CellAllocationMarks; internal GraphicsBuffer CellPatchIndices; internal GraphicsBuffer PatchCellIndices; - internal GraphicsBuffer NewCascadeOffsetsDevice; - internal int3[] NewCascadeOffsetsHost; - internal int3[] OldCascadeOffsetsHost; + internal GraphicsBuffer NewVolumeCascadeOffsetsDevice; + internal int3[] NewVolumeCascadeOffsetsHost; + internal int3[] OldVolumeCascadeOffsetsHost; internal uint VolumeSpatialResolution; - internal uint CascadeCount; + internal uint VolumeCascadeCount; } private class EvictionPassData @@ -339,10 +371,10 @@ private class EstimationPassData internal GraphicsBuffer PatchGeometries; internal GraphicsBuffer PatchStatistics; internal GraphicsBuffer CellPatchIndices; - internal GraphicsBuffer PatchCellIndices; - internal GraphicsBuffer CellAllocationMarks; - internal GraphicsBuffer CascadeOffsets; + internal GraphicsBuffer VolumeCascadeOffsets; internal GraphicsBuffer PunctualLightSamples; + internal GraphicsBuffer PatchAllocationRequestCount; + internal GraphicsBuffer PatchAllocationRequests; internal uint PunctualLightSampleCount; internal SurfaceCacheWorld World; internal float AlbedoBoost; @@ -351,7 +383,6 @@ private class EstimationPassData internal uint CascadeCount; internal bool MultiBounce; internal bool BouncePatchAllocation; - internal LocalKeyword EstimationBounceAllocKeyword; internal float ShortHysteresis; internal uint RingConfigOffset; internal uint SampleCount; @@ -359,6 +390,31 @@ private class EstimationPassData internal float VolumeVoxelMinSize; internal Vector3 VolumeTargetPos; internal GraphicsBuffer TraceScratchBuffer; + internal uint[] Zero; + } + + private class PatchAllocationPassData + { + internal ComputeShader Shader; + internal int KernelIndex; + internal uint3 ThreadGroupSize; + internal GraphicsBuffer Requests; + internal GraphicsBuffer RequestCount; + internal GraphicsBuffer PatchIrradiances0; + internal GraphicsBuffer PatchIrradiances1; + internal GraphicsBuffer PatchStatistics; + internal GraphicsBuffer PatchGeometries; + internal GraphicsBuffer PatchCellIndices; + internal GraphicsBuffer CellAllocationMarks; + internal GraphicsBuffer RingConfigBuffer; + internal GraphicsBuffer CellPatchIndices; + internal GraphicsBuffer VolumeCascadeOffsets; + internal uint RingConfigOffset; + internal uint VolumeSpatialResolution; + internal uint CascadeCount; + internal float VolumeVoxelMinSize; + internal Vector3 VolumeTargetPos; + internal uint FrameIndex; } private class SpatialFilterPassData @@ -368,7 +424,7 @@ private class SpatialFilterPassData internal GraphicsBuffer PatchGeometries; internal GraphicsBuffer RingConfigBuffer; internal GraphicsBuffer CellPatchIndices; - internal GraphicsBuffer CascadeOffsets; + internal GraphicsBuffer VolumeCascadeOffsets; internal ComputeShader Shader; internal int KernelIndex; internal uint3 ThreadGroupSize; @@ -413,10 +469,10 @@ internal static class ShaderIDs public static readonly int _EmissionTextures = Shader.PropertyToID("_EmissionTextures"); public static readonly int _VolumeTargetPos = Shader.PropertyToID("_VolumeTargetPos"); public static readonly int _EnvironmentCubemap = Shader.PropertyToID("_EnvironmentCubemap"); - public static readonly int _NewCascadeOffsets = Shader.PropertyToID("_NewCascadeOffsets"); - public static readonly int _OldCascadeOffsets = Shader.PropertyToID("_OldCascadeOffsets"); + public static readonly int _NewVolumeCascadeOffsets = Shader.PropertyToID("_NewVolumeCascadeOffsets"); + public static readonly int _OldVolumeCascadeOffsets = Shader.PropertyToID("_OldVolumeCascadeOffsets"); public static readonly int _VolumeSpatialResolution = Shader.PropertyToID("_VolumeSpatialResolution"); - public static readonly int _CascadeCount = Shader.PropertyToID("_CascadeCount"); + public static readonly int _VolumeCascadeCount = Shader.PropertyToID("_VolumeCascadeCount"); public static readonly int _SampleCount = Shader.PropertyToID("_SampleCount"); public static readonly int _MultiBounce = Shader.PropertyToID("_MultiBounce"); public static readonly int _VolumeVoxelMinSize = Shader.PropertyToID("_VolumeVoxelMinSize"); @@ -424,14 +480,19 @@ internal static class ShaderIDs public static readonly int _ShortHysteresis = Shader.PropertyToID("_ShortHysteresis"); public static readonly int _PatchCellIndices = Shader.PropertyToID("_PatchCellIndices"); public static readonly int _RingConfigBuffer = Shader.PropertyToID("_RingConfigBuffer"); + public static readonly int _Requests = Shader.PropertyToID("_Requests"); + public static readonly int _RequestCount = Shader.PropertyToID("_RequestCount"); public static readonly int _PunctualLights = Shader.PropertyToID("_PunctualLights"); + public static readonly int _PatchAllocationRequests = Shader.PropertyToID("_PatchAllocationRequests"); + public static readonly int _PatchAllocationRequestCount = Shader.PropertyToID("_PatchAllocationRequestCount"); public static readonly int _Radius = Shader.PropertyToID("_Radius"); public static readonly int _InputPatchIrradiances = Shader.PropertyToID("_InputPatchIrradiances"); public static readonly int _OutputPatchIrradiances = Shader.PropertyToID("_OutputPatchIrradiances"); public static readonly int _InputOutputPatchIrradiances = Shader.PropertyToID("_InputOutputPatchIrradiances"); public static readonly int _PatchIrradiances = Shader.PropertyToID("_PatchIrradiances"); public static readonly int _FrameIdx = Shader.PropertyToID("_FrameIdx"); - public static readonly int _CascadeOffsets = Shader.PropertyToID("_CascadeOffsets"); + public static readonly int _FrameIndex = Shader.PropertyToID("_FrameIndex"); + public static readonly int _VolumeCascadeOffsets = Shader.PropertyToID("_VolumeCascadeOffsets"); public static readonly int _PatchIrradiances0 = Shader.PropertyToID("_PatchIrradiances0"); public static readonly int _PatchIrradiances1 = Shader.PropertyToID("_PatchIrradiances1"); public static readonly int _PatchStatistics = Shader.PropertyToID("_PatchStatistics"); @@ -459,6 +520,7 @@ public SurfaceCache( _volume = new SurfaceCacheVolume(volParams.Resolution, volParams.CascadeCount, volParams.Size); _ringConfig = new SurfaceCacheRingConfig(); _patches = new SurfaceCachePatchList(patchCapacity); + _patchAllocationRequests = new SurfaceCachePatchAllocationRequestList(); _punctualLightSamples = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)punctualLightSampleCount, sizeof(float) * 17); } @@ -494,6 +556,10 @@ public void RecordPreparation(RenderGraph renderGraph, uint frameIdx) internal uint RecordPatchUpdate(RenderGraph renderGraph, uint frameIdx, SurfaceCacheWorld world) { RecordEstimation(renderGraph, frameIdx, world); + + if (_estimationParams.BouncePatchAllocation) + RecordPatchAllocation(renderGraph, frameIdx); + return RecordFiltering(renderGraph, frameIdx); } @@ -573,7 +639,7 @@ private uint RecordFiltering(RenderGraph renderGraph, uint frameIdx) passData.SampleCount = _patchFilteringParams.SpatialFilterSampleCount; passData.Radius = _patchFilteringParams.SpatialFilterRadius; passData.CellPatchIndices = Volume.CellPatchIndices; - passData.CascadeOffsets = Volume.CascadeOffsetBuffer; + passData.VolumeCascadeOffsets = Volume.CascadeOffsetBuffer; passData.RingConfigOffset = RingConfig.OffsetA; passData.VolumeTargetPos = Volume.TargetPos; @@ -613,6 +679,8 @@ private void RecordEstimation(RenderGraph renderGraph, uint frameIdx, SurfaceCac passData.PatchCapacity = Patches.Capacity; passData.PunctualLightSamplingShader = _resources.PunctualLightSamplingShader; passData.EstimationShader = _resources.EstimationShader; + passData.PatchAllocationRequestCount = _patchAllocationRequests.Count; + passData.PatchAllocationRequests = _patchAllocationRequests.Requests; passData.RingConfigBuffer = RingConfig.Buffer; passData.PatchIrradiances = Patches.Irradiances[0]; passData.PatchGeometries = Patches.Geometries; @@ -621,22 +689,20 @@ private void RecordEstimation(RenderGraph renderGraph, uint frameIdx, SurfaceCac passData.PunctualLightSampleCount = (uint)PunctualLightSamples.count; passData.World = world; passData.CellPatchIndices = Volume.CellPatchIndices; - passData.PatchCellIndices = Patches.CellIndices; - passData.CellAllocationMarks = Volume.CellAllocationMarks; passData.VolumeTargetPos = Volume.TargetPos; passData.FrameIdx = frameIdx; passData.AlbedoBoost = _albedoBoost; passData.EnvironmentIntensityMultiplier = world.GetEnvironmentIntensityMultiplier(); passData.VolumeSpatialResolution = Volume.SpatialResolution; - passData.CascadeOffsets = Volume.CascadeOffsetBuffer; + passData.VolumeCascadeOffsets = Volume.CascadeOffsetBuffer; passData.CascadeCount = Volume.CascadeCount; passData.MultiBounce = _estimationParams.MultiBounce; passData.BouncePatchAllocation = _estimationParams.BouncePatchAllocation; - passData.EstimationBounceAllocKeyword = _resources.EstimationBounceAllocKeyword; passData.ShortHysteresis = _shortHysteresis; passData.RingConfigOffset = RingConfig.OffsetA; passData.SampleCount = _estimationParams.SampleCount; passData.VolumeVoxelMinSize = Volume.VoxelMinSize; + passData.Zero = _zero; RayTracingHelper.ResizeScratchBufferForTrace(passData.EstimationShader, passData.PatchCapacity, 1, 1, ref _traceScratch); RayTracingHelper.ResizeScratchBufferForTrace(passData.PunctualLightSamplingShader, passData.PunctualLightSampleCount, 1, 1, ref _traceScratch); @@ -646,6 +712,36 @@ private void RecordEstimation(RenderGraph renderGraph, uint frameIdx, SurfaceCac } } + private void RecordPatchAllocation(RenderGraph renderGraph, uint frameIdx) + { + using (var builder = renderGraph.AddComputePass("Surface Cache Patch Allocation", out PatchAllocationPassData passData)) + { + passData.Shader = _resources.PatchAllocationShader; + passData.KernelIndex = _resources.PatchAllocationKernel; + passData.ThreadGroupSize = _resources.PatchAllocationKernelGroupSize; + passData.Requests = _patchAllocationRequests.Requests; + passData.RequestCount = _patchAllocationRequests.Count; + passData.PatchIrradiances0 = Patches.Irradiances[0]; + passData.PatchIrradiances1 = Patches.Irradiances[2]; + passData.PatchGeometries = Patches.Geometries; + passData.PatchStatistics = Patches.Statistics; + passData.PatchCellIndices = Patches.CellIndices; + passData.CellAllocationMarks = Volume.CellAllocationMarks; + passData.CellPatchIndices = Volume.CellPatchIndices; + passData.RingConfigBuffer = _ringConfig.Buffer; + passData.RingConfigOffset = _ringConfig.OffsetA; + passData.CascadeCount = Volume.CascadeCount; + passData.VolumeSpatialResolution = Volume.SpatialResolution; + passData.VolumeVoxelMinSize = Volume.VoxelMinSize; + passData.VolumeTargetPos = Volume.TargetPos; + passData.VolumeCascadeOffsets = Volume.CascadeOffsetBuffer; + passData.FrameIndex = frameIdx; + + builder.AllowGlobalStateModification(true); // Set to ensure ordering. + builder.SetRenderFunc((PatchAllocationPassData data, ComputeGraphContext cgContext) => AllocatePatches(data, cgContext)); + } + } + private void RecordScrolling(RenderGraph renderGraph) { bool cascadesChanged = false; @@ -675,10 +771,10 @@ private void RecordScrolling(RenderGraph renderGraph) passData.CellPatchIndices = Volume.CellPatchIndices; passData.PatchCellIndices = Patches.CellIndices; passData.VolumeSpatialResolution = Volume.SpatialResolution; - passData.NewCascadeOffsetsDevice = Volume.CascadeOffsetBuffer; - passData.NewCascadeOffsetsHost = Volume.CascadeOffsets; - passData.OldCascadeOffsetsHost = oldCascadeOffsets.ToArray(); - passData.CascadeCount = Volume.CascadeCount; + passData.NewVolumeCascadeOffsetsDevice = Volume.CascadeOffsetBuffer; + passData.NewVolumeCascadeOffsetsHost = Volume.CascadeOffsets; + passData.OldVolumeCascadeOffsetsHost = oldCascadeOffsets.ToArray(); + passData.VolumeCascadeCount = Volume.CascadeCount; builder.AllowGlobalStateModification(true); // Set to ensure ordering. builder.SetRenderFunc((ScrollingPassData data, ComputeGraphContext cgContext) => Scroll(data, cgContext)); @@ -686,12 +782,45 @@ private void RecordScrolling(RenderGraph renderGraph) } } + static void AllocatePatches(PatchAllocationPassData passData, ComputeGraphContext cgContext) + { + var cmd = cgContext.cmd; + var shader = passData.Shader; + var kernelIndex = passData.KernelIndex; + + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._Requests, passData.Requests); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._RequestCount, passData.RequestCount); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchIrradiances0, passData.PatchIrradiances0); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchIrradiances1, passData.PatchIrradiances1); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchStatistics, passData.PatchStatistics); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchGeometries, passData.PatchGeometries); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchCellIndices, passData.PatchCellIndices); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CellPatchIndices, passData.CellPatchIndices); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CellAllocationMarks, passData.CellAllocationMarks); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._RingConfigBuffer, passData.RingConfigBuffer); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._VolumeCascadeOffsets, passData.VolumeCascadeOffsets); + cmd.SetComputeIntParam(shader, ShaderIDs._RingConfigOffset, (int)passData.RingConfigOffset); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeSpatialResolution, (int)passData.VolumeSpatialResolution); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeCascadeCount, (int)passData.CascadeCount); + cmd.SetComputeFloatParam(shader, ShaderIDs._VolumeVoxelMinSize, passData.VolumeVoxelMinSize); + cmd.SetComputeVectorParam(shader, ShaderIDs._VolumeTargetPos, passData.VolumeTargetPos); + cmd.SetComputeIntParam(shader, ShaderIDs._FrameIndex, (int)passData.FrameIndex); + + uint3 groupCount = DivUp(new uint3(SurfaceCachePatchAllocationRequestList.RequestMax, 1, 1), passData.ThreadGroupSize); + cmd.DispatchCompute(shader, kernelIndex, (int)groupCount.x, (int)groupCount.y, 1); + } + static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) { var cmd = CommandBufferHelpers.GetNativeCommandBuffer(graphCtx.cmd); var punctualLightBuffer = data.World.GetPunctualLightBuffer(); var punctualLightCount = (int)data.World.GetPunctualLightCount(); + if (data.BouncePatchAllocation) + { + cmd.SetBufferData(data.PatchAllocationRequestCount, data.Zero); + } + if (punctualLightCount != 0) { var shader = data.PunctualLightSamplingShader; @@ -709,17 +838,18 @@ static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) { var shader = data.EstimationShader; - shader.SetKeyword(cmd, data.EstimationBounceAllocKeyword, data.BouncePatchAllocation); shader.SetBufferParam(cmd, ShaderIDs._PunctualLights, punctualLightBuffer); + shader.SetBufferParam(cmd, ShaderIDs._PatchAllocationRequestCount, data.PatchAllocationRequestCount); + shader.SetBufferParam(cmd, ShaderIDs._PatchAllocationRequests, data.PatchAllocationRequests); shader.SetBufferParam(cmd, ShaderIDs._RingConfigBuffer, data.RingConfigBuffer); shader.SetBufferParam(cmd, ShaderIDs._PunctualLightSamples, data.PunctualLightSamples); shader.SetBufferParam(cmd, ShaderIDs._PatchIrradiances, data.PatchIrradiances); shader.SetBufferParam(cmd, ShaderIDs._PatchGeometries, data.PatchGeometries); shader.SetBufferParam(cmd, ShaderIDs._PatchStatistics, data.PatchStatistics); - shader.SetBufferParam(cmd, ShaderIDs._CascadeOffsets, data.CascadeOffsets); + shader.SetBufferParam(cmd, ShaderIDs._VolumeCascadeOffsets, data.VolumeCascadeOffsets); shader.SetIntParam(cmd, ShaderIDs._FrameIdx, (int)data.FrameIdx); shader.SetIntParam(cmd, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); - shader.SetIntParam(cmd, ShaderIDs._CascadeCount, (int)data.CascadeCount); + shader.SetIntParam(cmd, ShaderIDs._VolumeCascadeCount, (int)data.CascadeCount); shader.SetIntParam(cmd, ShaderIDs._SampleCount, (int)data.SampleCount); shader.SetIntParam(cmd, ShaderIDs._MultiBounce, data.MultiBounce ? 1 : 0); shader.SetFloatParam(cmd, ShaderIDs._VolumeVoxelMinSize, data.VolumeVoxelMinSize); @@ -727,8 +857,6 @@ static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) shader.SetFloatParam(cmd, ShaderIDs._ShortHysteresis, data.ShortHysteresis); shader.SetIntParam(cmd, ShaderIDs._RingConfigOffset, (int)data.RingConfigOffset); shader.SetBufferParam(cmd, ShaderIDs._CellPatchIndices, data.CellPatchIndices); - shader.SetBufferParam(cmd, ShaderIDs._PatchCellIndices, data.PatchCellIndices); - shader.SetBufferParam(cmd, ShaderIDs._CellAllocationMarks, data.CellAllocationMarks); shader.SetVectorParam(cmd, ShaderIDs._VolumeTargetPos, data.VolumeTargetPos); shader.SetTextureParam(cmd, ShaderIDs._EnvironmentCubemap, data.World.GetEnvironmentTexture()); shader.SetBufferParam(cmd, ShaderIDs._MaterialEntries, data.World.GetMaterialListBuffer()); @@ -738,6 +866,7 @@ static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) shader.SetFloatParam(cmd, ShaderIDs._EnvironmentIntensityMultiplier, data.EnvironmentIntensityMultiplier); shader.SetFloatParam(cmd, ShaderIDs._MaterialAtlasTexelSize, GetMaterialAtlasTexelSize(data.World.GetMaterialAlbedoTextures())); shader.SetIntParam(cmd, ShaderIDs._PunctualLightCount, punctualLightCount); + shader.SetIntParam(cmd, ShaderIDs._BouncePatchAllocation, data.BouncePatchAllocation ? 1 : 0); var (dirLightDirection, dirLightIntensity) = GetDirectionalLightUniforms(data.World.GetDirectionalLight()); shader.SetVectorParam(cmd, ShaderIDs._DirectionalLightDirection, dirLightDirection); @@ -746,7 +875,6 @@ static void Estimate(EstimationPassData data, UnsafeGraphContext graphCtx) data.World.GetAccelerationStructure().Bind(cmd, "_RayTracingAccelerationStructure", shader); shader.Dispatch(cmd, data.TraceScratchBuffer, data.PatchCapacity, 1, 1); - shader.SetKeyword(cmd, data.EstimationBounceAllocKeyword, false); } } @@ -804,9 +932,9 @@ static void FilterSpatially(SpatialFilterPassData data, ComputeGraphContext cgCo cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._OutputPatchIrradiances, data.OutputPatchIrradiances); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchGeometries, data.PatchGeometries); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CellPatchIndices, data.CellPatchIndices); - cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CascadeOffsets, data.CascadeOffsets); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._VolumeCascadeOffsets, data.VolumeCascadeOffsets); cmd.SetComputeIntParam(shader, ShaderIDs._FrameIdx, (int)data.FrameIdx); - cmd.SetComputeIntParam(shader, ShaderIDs._CascadeCount, (int)data.CascadeCount); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeCascadeCount, (int)data.CascadeCount); cmd.SetComputeIntParam(shader, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); cmd.SetComputeFloatParam(shader, ShaderIDs._VolumeVoxelMinSize, data.VolumeVoxelMinSize); cmd.SetComputeIntParam(shader, ShaderIDs._SampleCount, (int)data.SampleCount); @@ -841,37 +969,38 @@ public void Dispose() _patches.Dispose(); _punctualLightSamples.Dispose(); _traceScratch?.Dispose(); + _patchAllocationRequests.Dispose(); } private static uint3 DivUp(uint3 x, uint3 y) => (x + y - 1) / y; static void Scroll(ScrollingPassData data, ComputeGraphContext cgContext) { - Debug.Assert(data.NewCascadeOffsetsHost.Length == data.OldCascadeOffsetsHost.Length); - uint cascadeCount = (uint)data.NewCascadeOffsetsHost.Length; + Debug.Assert(data.NewVolumeCascadeOffsetsHost.Length == data.OldVolumeCascadeOffsetsHost.Length); + uint cascadeCount = (uint)data.NewVolumeCascadeOffsetsHost.Length; var cmd = cgContext.cmd; - cmd.SetBufferData(data.NewCascadeOffsetsDevice, data.NewCascadeOffsetsHost); + cmd.SetBufferData(data.NewVolumeCascadeOffsetsDevice, data.NewVolumeCascadeOffsetsHost); cmd.SetComputeBufferParam(data.Shader, data.KernelIndex, ShaderIDs._CellAllocationMarks, data.CellAllocationMarks); cmd.SetComputeBufferParam(data.Shader, data.KernelIndex, ShaderIDs._CellPatchIndices, data.CellPatchIndices); - cmd.SetComputeBufferParam(data.Shader, data.KernelIndex, ShaderIDs._NewCascadeOffsets, data.NewCascadeOffsetsDevice); + cmd.SetComputeBufferParam(data.Shader, data.KernelIndex, ShaderIDs._NewVolumeCascadeOffsets, data.NewVolumeCascadeOffsetsDevice); cmd.SetComputeBufferParam(data.Shader, data.KernelIndex, ShaderIDs._PatchCellIndices, data.PatchCellIndices); cmd.SetComputeIntParam(data.Shader, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); - cmd.SetComputeIntParam(data.Shader, ShaderIDs._CascadeCount, (int)data.CascadeCount); + cmd.SetComputeIntParam(data.Shader, ShaderIDs._VolumeCascadeCount, (int)data.VolumeCascadeCount); { - var oldCascadeOffsetsInts = new int[data.OldCascadeOffsetsHost.Length * 4]; + var oldCascadeOffsetsInts = new int[data.OldVolumeCascadeOffsetsHost.Length * 4]; for (uint cascadeIdx = 0; cascadeIdx < cascadeCount; ++cascadeIdx) { - oldCascadeOffsetsInts[cascadeIdx * 4] = data.OldCascadeOffsetsHost[cascadeIdx][0]; - oldCascadeOffsetsInts[cascadeIdx * 4 + 1] = data.OldCascadeOffsetsHost[cascadeIdx][1]; - oldCascadeOffsetsInts[cascadeIdx * 4 + 2] = data.OldCascadeOffsetsHost[cascadeIdx][2]; + oldCascadeOffsetsInts[cascadeIdx * 4] = data.OldVolumeCascadeOffsetsHost[cascadeIdx][0]; + oldCascadeOffsetsInts[cascadeIdx * 4 + 1] = data.OldVolumeCascadeOffsetsHost[cascadeIdx][1]; + oldCascadeOffsetsInts[cascadeIdx * 4 + 2] = data.OldVolumeCascadeOffsetsHost[cascadeIdx][2]; oldCascadeOffsetsInts[cascadeIdx * 4 + 3] = 0; } - cmd.SetComputeIntParams(data.Shader, ShaderIDs._OldCascadeOffsets, oldCascadeOffsetsInts); + cmd.SetComputeIntParams(data.Shader, ShaderIDs._OldVolumeCascadeOffsets, oldCascadeOffsetsInts); } - uint3 groupCount = DivUp(new uint3(data.VolumeSpatialResolution, data.VolumeSpatialResolution, data.VolumeSpatialResolution * data.CascadeCount), data.ThreadGroupSize); + uint3 groupCount = DivUp(new uint3(data.VolumeSpatialResolution, data.VolumeSpatialResolution, data.VolumeSpatialResolution * data.VolumeCascadeCount), data.ThreadGroupSize); cmd.DispatchCompute(data.Shader, data.KernelIndex, (int)groupCount.x, (int)groupCount.y, (int)groupCount.z); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheRenderPipelineResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheRenderPipelineResources.cs index d6b45d03cd0..71eabe87ef2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheRenderPipelineResources.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheRenderPipelineResources.cs @@ -29,6 +29,9 @@ sealed class SurfaceCacheRenderPipelineResourceSet : IRenderPipelineResources [ResourcePath("Runtime/Lighting/SurfaceCache/Eviction.compute")] public ComputeShader m_EvictionShader; + [ResourcePath("Runtime/Lighting/SurfaceCache/PatchAllocation.compute")] + public ComputeShader m_PatchAllocationShader; + [ResourcePath("Runtime/Lighting/SurfaceCache/PunctualLightSampling.urtshader")] public ComputeShader m_PunctualLightSamplingComputeShader; @@ -94,6 +97,12 @@ public ComputeShader evictionShader get => m_EvictionShader; set => this.SetValueAndNotify(ref m_EvictionShader, value, nameof(m_EvictionShader)); } + + public ComputeShader patchAllocationShader + { + get => m_PatchAllocationShader; + set => this.SetValueAndNotify(ref m_PatchAllocationShader, value, nameof(m_PatchAllocationShader)); + } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/Debug.compute b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/Debug.compute index af76d5b0487..1bbf8496f94 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/Debug.compute +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/Debug.compute @@ -15,7 +15,7 @@ StructuredBuffer _PatchCellIndices; StructuredBuffer _PatchGeometries; RWStructuredBuffer _PatchStatistics; StructuredBuffer _CellPatchIndices; -StructuredBuffer _CascadeOffsets; +StructuredBuffer _VolumeCascadeOffsets; RWTexture2D _Result; Texture2D _ScreenDepths; @@ -24,7 +24,7 @@ Texture2D _ScreenFlatNormals; uint _RingConfigOffset; uint _VolumeSpatialResolution; -uint _CascadeCount; +uint _VolumeCascadeCount; uint _ViewMode; uint _ShowSamplePosition; float4x4 _ClipToWorldTransform; @@ -98,15 +98,15 @@ void Visualize(uint2 threadIdx : SV_DispatchThreadID) volumeParams.targetPos = _VolumeTargetPos; volumeParams.spatialResolution = _VolumeSpatialResolution; volumeParams.voxelMinSize = _VolumeVoxelMinSize; - volumeParams.cascadeOffsets = _CascadeOffsets; - volumeParams.cascadeCount = _CascadeCount; + volumeParams.cascadeOffsets = _VolumeCascadeOffsets; + volumeParams.cascadeCount = _VolumeCascadeCount; PatchUtil::VolumePositionResolution posResolution = PatchUtil::ResolveVolumePosition(worldPos, volumeParams); output = float3(1.0f, 0.0f, 1.0f); if (posResolution.isValid()) { const uint directionIdx = PatchUtil::GetDirectionIndex(worldFlatNormal, PatchUtil::volumeAngularResolution); - const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(posResolution.positionVolumeSpace, _VolumeSpatialResolution, _CascadeOffsets[posResolution.cascadeIdx]); + const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(posResolution.positionVolumeSpace, _VolumeSpatialResolution, _VolumeCascadeOffsets[posResolution.cascadeIdx]); const uint cellIdx = PatchUtil::GetCellIndex(posResolution.cascadeIdx, positionStorageSpace, directionIdx, _VolumeSpatialResolution, PatchUtil::volumeAngularResolution); const uint patchIdx = _CellPatchIndices[cellIdx]; const bool hasPatch = (patchIdx != PatchUtil::invalidPatchIndex); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/PatchAllocation.compute b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/PatchAllocation.compute index d523b912db9..12a2f98b0be 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/PatchAllocation.compute +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/PatchAllocation.compute @@ -19,7 +19,7 @@ RWStructuredBuffer _PatchIrradiances1; RWStructuredBuffer _CellAllocationMarks; RWStructuredBuffer _CellPatchIndices; RWStructuredBuffer _PatchCellIndices; -StructuredBuffer _CascadeOffsets; +StructuredBuffer _VolumeCascadeOffsets; Texture2D _CurrentFullResScreenDepths; Texture2D _CurrentFullResScreenFlatNormals; @@ -33,7 +33,7 @@ Texture2D _PreviousLowResScreenNdcDepths; uint _FrameIdx; uint _VolumeSpatialResolution; float _VolumeVoxelMinSize; -uint _CascadeCount; +uint _VolumeCascadeCount; uint _RingConfigOffset; float4x4 _CurrentClipToWorldTransform; float4x4 _PreviousClipToWorldTransform; @@ -119,15 +119,15 @@ void Allocate(uint2 lowResPixelPos : SV_DispatchThreadID) volumeParams.targetPos = _VolumeTargetPos; volumeParams.spatialResolution = _VolumeSpatialResolution; volumeParams.voxelMinSize = _VolumeVoxelMinSize; - volumeParams.cascadeOffsets = _CascadeOffsets; - volumeParams.cascadeCount = _CascadeCount; + volumeParams.cascadeOffsets = _VolumeCascadeOffsets; + volumeParams.cascadeCount = _VolumeCascadeCount; PatchUtil::VolumePositionResolution patchPosResolution = PatchUtil::ResolveVolumePosition(sourceWorldPosition, volumeParams); if (patchPosResolution.isValid()) { const uint directionIdx = PatchUtil::GetDirectionIndex(sourceWorldFlatNormal, PatchUtil::volumeAngularResolution); - const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(patchPosResolution.positionVolumeSpace, _VolumeSpatialResolution, _CascadeOffsets[patchPosResolution.cascadeIdx]); + const uint3 positionStorageSpace = PatchUtil::ConvertVolumeSpaceToStorageSpace(patchPosResolution.positionVolumeSpace, _VolumeSpatialResolution, _VolumeCascadeOffsets[patchPosResolution.cascadeIdx]); const uint cellIdx = PatchUtil::GetCellIndex(patchPosResolution.cascadeIdx, positionStorageSpace, directionIdx, _VolumeSpatialResolution, PatchUtil::volumeAngularResolution); PatchUtil::PatchIndexResolutionResult resolutionResult = PatchUtil::ResolvePatchIndex( diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/ScreenResolveLookup.compute b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/ScreenResolveLookup.compute index 176d5c85023..daf587f549c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/ScreenResolveLookup.compute +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/ScreenResolveLookup.compute @@ -20,10 +20,10 @@ RWStructuredBuffer _PatchStatistics; StructuredBuffer _PatchIrradiances; StructuredBuffer _CellPatchIndices; -StructuredBuffer _CascadeOffsets; +StructuredBuffer _VolumeCascadeOffsets; uint _VolumeSpatialResolution; -uint _CascadeCount; +uint _VolumeCascadeCount; uint _SampleCount; float _VolumeVoxelMinSize; float4x4 _ClipToWorldTransform; @@ -62,11 +62,11 @@ void Lookup(uint2 lowResPixelPos : SV_DispatchThreadID) volumeParams.targetPos = _VolumeTargetPos; volumeParams.spatialResolution = _VolumeSpatialResolution; volumeParams.voxelMinSize = _VolumeVoxelMinSize; - volumeParams.cascadeOffsets = _CascadeOffsets; - volumeParams.cascadeCount = _CascadeCount; + volumeParams.cascadeOffsets = _VolumeCascadeOffsets; + volumeParams.cascadeCount = _VolumeCascadeCount; - const int cascadeResolution = PatchUtil::ResolveCascadeIndex(_VolumeTargetPos, worldPos, _VolumeSpatialResolution, _CascadeCount, _VolumeVoxelMinSize); - const uint cascadeIdx = cascadeResolution == -1 ? _CascadeCount - 1 : cascadeResolution; + const int cascadeResolution = PatchUtil::ResolveCascadeIndex(_VolumeTargetPos, worldPos, _VolumeSpatialResolution, _VolumeCascadeCount, _VolumeVoxelMinSize); + const uint cascadeIdx = cascadeResolution == -1 ? _VolumeCascadeCount - 1 : cascadeResolution; const float voxelSize = PatchUtil::GetVoxelSize(_VolumeVoxelMinSize, cascadeIdx); SphericalHarmonics::RGBL1 irradianceSum = (SphericalHarmonics::RGBL1)0; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs index 1a3140df198..7e109b4baf7 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs @@ -161,9 +161,9 @@ internal static class ShaderIDs public static readonly int _VolumeTargetPos = Shader.PropertyToID("_VolumeTargetPos"); public static readonly int _FullResPixelOffset = Shader.PropertyToID("_FullResPixelOffset"); public static readonly int _LowResScreenSize = Shader.PropertyToID("_LowResScreenSize"); - public static readonly int _CascadeCount = Shader.PropertyToID("_CascadeCount"); + public static readonly int _VolumeCascadeCount = Shader.PropertyToID("_VolumeCascadeCount"); public static readonly int _VolumeVoxelMinSize = Shader.PropertyToID("_VolumeVoxelMinSize"); - public static readonly int _CascadeOffsets = Shader.PropertyToID("_CascadeOffsets"); + public static readonly int _VolumeCascadeOffsets = Shader.PropertyToID("_VolumeCascadeOffsets"); public static readonly int _PatchCellIndices = Shader.PropertyToID("_PatchCellIndices"); } @@ -816,10 +816,10 @@ static void LookupScreenIrradiance(ScreenIrradianceLookupPassData data, ComputeG cmd.SetComputeTextureParam(shader, kernelIndex, ShaderIDs._ScreenFlatNormals, data.FullResFlatNormals); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CellPatchIndices, data.CellPatchIndices); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchIrradiances, data.PatchIrradiances); - cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CascadeOffsets, data.CascadeOffsets); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._VolumeCascadeOffsets, data.CascadeOffsets); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchStatistics, data.PatchStatistics); cmd.SetComputeIntParam(shader, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); - cmd.SetComputeIntParam(shader, ShaderIDs._CascadeCount, (int)data.VolumeCascadeCount); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeCascadeCount, (int)data.VolumeCascadeCount); cmd.SetComputeIntParam(shader, ShaderIDs._SampleCount, (int)data.SampleCount); cmd.SetComputeIntParam(shader, ShaderIDs._FrameIdx, (int)data.FrameIndex); cmd.SetComputeFloatParam(shader, ShaderIDs._VolumeVoxelMinSize, data.VolumeVoxelMinSize); @@ -886,10 +886,10 @@ static void AllocatePatches(PatchAllocationPassData data, ComputeGraphContext cg cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchGeometries, data.PatchGeometries); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchCellIndices, data.PatchCellIndices); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchStatistics, data.PatchStatistics); - cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CascadeOffsets, data.CascadeOffsets); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._VolumeCascadeOffsets, data.CascadeOffsets); cmd.SetComputeIntParam(shader, ShaderIDs._FrameIdx, (int)data.FrameIdx); cmd.SetComputeIntParam(shader, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); - cmd.SetComputeIntParam(shader, ShaderIDs._CascadeCount, (int)data.VolumeCascadeCount); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeCascadeCount, (int)data.VolumeCascadeCount); cmd.SetComputeIntParam(shader, ShaderIDs._RingConfigOffset, (int)data.RingConfigOffset); cmd.SetComputeIntParams(shader, ShaderIDs._FullResPixelOffset, (int)data.FullResPixelOffset.x, (int)data.FullResPixelOffset.y); cmd.SetComputeIntParams(shader, ShaderIDs._LowResScreenSize, (int)data.LowResScreenSize.x, (int)data.LowResScreenSize.y); @@ -916,12 +916,12 @@ static void RenderDebug(DebugPassData data, ComputeGraphContext cgContext) cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._RingConfigBuffer, data.RingConfigBuffer); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchIrradiances, data.PatchIrradiances); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchGeometries, data.PatchGeometries); - cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._CascadeOffsets, data.CascadeOffsets); + cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._VolumeCascadeOffsets, data.CascadeOffsets); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchCellIndices, data.PatchCellIndices); cmd.SetComputeBufferParam(shader, kernelIndex, ShaderIDs._PatchStatistics, data.PatchStatistics); cmd.SetComputeIntParam(shader, ShaderIDs._VolumeSpatialResolution, (int)data.VolumeSpatialResolution); - cmd.SetComputeIntParam(shader, ShaderIDs._CascadeCount, (int)data.VolumeCascadeCount); + cmd.SetComputeIntParam(shader, ShaderIDs._VolumeCascadeCount, (int)data.VolumeCascadeCount); cmd.SetComputeIntParam(shader, ShaderIDs._ViewMode, (int)data.ViewMode); cmd.SetComputeIntParam(shader, ShaderIDs._FrameIdx, (int)data.FrameIndex); cmd.SetComputeIntParam(shader, ShaderIDs._ShowSamplePosition, data.ShowSamplePosition ? 1 : 0); From dadcc99ff2d6ec4cee5be2d72ad7e4baac773159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Chapelain?= Date: Tue, 21 Apr 2026 00:56:11 +0000 Subject: [PATCH 16/56] [Core] Fix SRP Sample dependency importer --- .../SampleDependencyImporter.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) 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 c52489bb120..6ae1a448d9c 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.IO; using UnityEditor; @@ -40,7 +39,6 @@ static SampleDependencyImporter() PackageInfo m_PackageInfo; SampleList m_SampleList; - List m_Samples; VisualElement injectingElement; VisualElement _panelRoot; @@ -100,6 +98,7 @@ internal void RefreshSampleButtons() var bound = Mathf.Min(sampleContainers.Count, m_SampleList.samples.Length); + // Foreach sample for (int i=0; i { ImportSampleDependencies(index); - using (var ev = NavigationSubmitEvent.GetPooled()) + // After importing the dependencies, we can call the package manager API import logic. + foreach (Sample sample in Sample.FindByPackage(m_PackageInfo.name, m_PackageInfo.version)) { - ev.target = importButton; - importButton.SendEvent(ev); + if (sample.displayName == m_SampleList.samples[index].displayName) + { + sample.Import(Sample.ImportOptions.HideImportWindow | Sample.ImportOptions.OverridePreviousImports); + } } + }; } else // We may need to update the button text after the sample import here. From fb2c4f647bad7eaaf702f2841c578234198fd743 Mon Sep 17 00:00:00 2001 From: Justin Schwartz Date: Tue, 21 Apr 2026 01:47:48 +0000 Subject: [PATCH 17/56] Updated `LensFlareCommonSRP` and `LensFlareComponentSRP` to work with CoreCLR --- .../PostProcessing/LensFlareCommonSRP.cs | 215 +++++++++++------- .../PostProcessing/LensFlareComponentSRP.cs | 15 +- 2 files changed, 143 insertions(+), 87 deletions(-) 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 346b28985b8..694607aae6e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs @@ -18,22 +18,23 @@ namespace UnityEngine.Rendering /// public sealed class LensFlareCommonSRP { - private static LensFlareCommonSRP m_Instance = null; - private static readonly object m_Padlock = new object(); + private static LensFlareCommonSRP s_Instance = null; + private static readonly object s_Padlock = new object(); + /// - /// Class describing internal information stored to describe a shown LensFlare + /// Struct describing internal information stored to describe a shown LensFlare /// - internal class LensFlareCompInfo + internal readonly struct LensFlareCompInfo { /// /// Index used to compute Occlusion in a fixed order /// - internal int index; + internal readonly int index; /// /// Component used /// - internal LensFlareComponentSRP comp; + internal readonly LensFlareComponentSRP comp; internal LensFlareCompInfo(int idx, LensFlareComponentSRP cmp) { @@ -42,14 +43,14 @@ internal LensFlareCompInfo(int idx, LensFlareComponentSRP cmp) } } - private static List m_Data = new List(); - private static List m_AvailableIndicies = new List(); + const int k_DefaultMaxLensFlareWithOcclusion = 128; + const int k_DefaultMaxFlareWithOcclusionTemporalSample = 8; + const int k_DefaultMergeNeeded = 1; /// /// Defines how many lens flare with occlusion are supported in the view at any time. /// - public static int maxLensFlareWithOcclusion = 128; - + public static int maxLensFlareWithOcclusion = k_DefaultMaxLensFlareWithOcclusion; /// /// With TAA Occlusion jitter depth, thought frame on HDRP. @@ -58,13 +59,13 @@ internal LensFlareCompInfo(int idx, LensFlareComponentSRP cmp) /// If this value change that could implies an implementation modification on: /// com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/LensFlareMergeOcclusionDataDriven.compute /// - public static int maxLensFlareWithOcclusionTemporalSample = 8; + public static int maxLensFlareWithOcclusionTemporalSample = k_DefaultMaxFlareWithOcclusionTemporalSample; /// /// Set to 1 to enable temporal sample merge. /// Set to 0 to disable temporal sample merge (must support 16 bit textures, and the occlusion merge must be written in the last texel (vertical) of the lens flare texture. /// - public static int mergeNeeded = 1; + public static int mergeNeeded = k_DefaultMergeNeeded; /// /// occlusion texture either provided or created automatically by the SRP for lens flare. @@ -73,9 +74,14 @@ internal LensFlareCompInfo(int idx, LensFlareComponentSRP cmp) /// Merge results must be done by the SRP and stored in the [(lens flareIndex), (maxLensFlareWithOcclusionTemporalSample + 1)] coordinate. /// Note: It's not supported on OpenGL3 and OpenGLCore /// - public static RTHandle occlusionRT = null; + public static RTHandle occlusionRT => Instance.m_OcclusionRT; + + private RTHandle m_OcclusionRT; - private static int frameIdx = 0; + private List m_Data = new List(); + private List m_AvailableIndicies = new List(); + + private int frameIdx = 0; internal static readonly int _FlareOcclusionPermutation = Shader.PropertyToID("_FlareOcclusionPermutation"); internal static readonly int _FlareOcclusionRemapTex = Shader.PropertyToID("_FlareOcclusionRemapTex"); @@ -127,10 +133,11 @@ static bool CheckOcclusionBasedOnDeviceType() #if UNITY_SERVER return false; #else - return SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3 && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.WebGPU; + var graphicsDeviceType = SystemInfo.graphicsDeviceType; + return graphicsDeviceType != GraphicsDeviceType.Null && + graphicsDeviceType != GraphicsDeviceType.OpenGLES3 && + graphicsDeviceType != GraphicsDeviceType.OpenGLCore && + graphicsDeviceType != GraphicsDeviceType.WebGPU; #endif } @@ -165,7 +172,12 @@ static GraphicsFormat GetOcclusionRTFormat() /// /// You usually call `Initialize` in the constructor. /// - static public void Initialize() + public static void Initialize() + { + Instance.Init(); + } + + void Init() { frameIdx = 0; if (IsOcclusionRTCompatible()) @@ -173,9 +185,9 @@ static public void Initialize() // The height of occlusion texture is: // - '1': when no temporal accumulation // - 'maxLensFlareWithOcclusionTemporalSample + 1': for temporal accumulation, useful when TAA enabled - if (occlusionRT == null) + if (m_OcclusionRT == null) { - occlusionRT = RTHandles.Alloc( + m_OcclusionRT = RTHandles.Alloc( width: maxLensFlareWithOcclusion, height: Mathf.Max(mergeNeeded * (maxLensFlareWithOcclusionTemporalSample + 1), 1), format: GetOcclusionRTFormat(), @@ -192,15 +204,17 @@ static public void Initialize() /// /// Usually, `Dispose` is called in the function. /// - static public void Dispose() + public static void Dispose() { - if (IsOcclusionRTCompatible()) + s_Instance?.Cleanup(); + } + + void Cleanup() + { + if (m_OcclusionRT != null) { - if (occlusionRT != null) - { - RTHandles.Release(occlusionRT); - occlusionRT = null; - } + RTHandles.Release(occlusionRT); + m_OcclusionRT = null; } } @@ -214,22 +228,18 @@ public static LensFlareCommonSRP Instance { get { - if (m_Instance == null) + if (s_Instance == null) { - lock (m_Padlock) + lock (s_Padlock) { - if (m_Instance == null) - { - m_Instance = new LensFlareCommonSRP(); - } + s_Instance ??= new LensFlareCommonSRP(); } } - return m_Instance; + + return s_Instance; } } - private System.Collections.Generic.List Data { get { return LensFlareCommonSRP.m_Data; } } - /// /// Checks if at least one lens flare has been added to the pool. /// @@ -245,19 +255,25 @@ public static LensFlareCommonSRP Instance /// `true` if no lens flare were added public bool IsEmpty() { - return Data.Count == 0; + return m_Data.Count == 0; } int GetNextAvailableIndex() { + int nextIndex; + if (m_AvailableIndicies.Count == 0) - return m_Data.Count; + { + nextIndex = m_Data.Count; + } else { - int nextIndex = m_AvailableIndicies[m_AvailableIndicies.Count - 1]; - m_AvailableIndicies.RemoveAt(m_AvailableIndicies.Count - 1); - return nextIndex; + int end = m_AvailableIndicies.Count - 1; + nextIndex = m_AvailableIndicies[end]; + m_AvailableIndicies.RemoveAt(end); } + + return nextIndex; } /// @@ -270,9 +286,19 @@ int GetNextAvailableIndex() /// The new data added public void AddData(LensFlareComponentSRP newData) { - Debug.Assert(Instance == this, "LensFlareCommonSRP can have only one instance"); + Debug.Assert(s_Instance == this, "LensFlareCommonSRP can have only one instance"); - if (!m_Data.Exists(x => x.comp == newData)) + bool found = false; + foreach (LensFlareCompInfo data in m_Data) + { + if (data.comp == newData) + { + found = true; + break; + } + } + + if (!found) { m_Data.Add(new LensFlareCompInfo(GetNextAvailableIndex(), newData)); } @@ -287,14 +313,31 @@ public void AddData(LensFlareComponentSRP newData) /// The data which exist in the pool public void RemoveData(LensFlareComponentSRP data) { - Debug.Assert(Instance == this, "LensFlareCommonSRP can have only one instance"); + Debug.Assert(s_Instance == this, "LensFlareCommonSRP can have only one instance"); - LensFlareCompInfo info = m_Data.Find(x => x.comp == data); - if (info != null) + int index = -1; + for (int i = 0, imax = m_Data.Count; i < imax; ++i) { - int newIndex = info.index; - m_Data.Remove(info); - m_AvailableIndicies.Add(newIndex); + if (m_Data[i].comp == data) + { + index = i; + break; + } + } + + if (index >= 0) + { + LensFlareCompInfo info = m_Data[index]; + m_AvailableIndicies.Add(info.index); + + int end = m_Data.Count - 1; + if (index != end) + { + m_Data[index] = m_Data[end]; + } + + m_Data.RemoveAt(end); + if (m_Data.Count == 0) m_AvailableIndicies.Clear(); } @@ -341,7 +384,7 @@ public void RemoveData(LensFlareComponentSRP data) /// /// /// Attenuation Factor - static public float ShapeAttenuationPointLight() + public static float ShapeAttenuationPointLight() { return 1.0f; } @@ -388,7 +431,7 @@ static public float ShapeAttenuationPointLight() /// } /// /// - static public float ShapeAttenuationDirLight(Vector3 forward, Vector3 wo) + public static float ShapeAttenuationDirLight(Vector3 forward, Vector3 wo) { return Mathf.Max(Vector3.Dot(-forward, wo), 0.0f); } @@ -437,7 +480,7 @@ static public float ShapeAttenuationDirLight(Vector3 forward, Vector3 wo) /// } /// /// - static public float ShapeAttenuationSpotConeLight(Vector3 forward, Vector3 wo, float spotAngle, float innerSpotPercent01) + public static float ShapeAttenuationSpotConeLight(Vector3 forward, Vector3 wo, float spotAngle, float innerSpotPercent01) { float outerDot = Mathf.Max(Mathf.Cos(0.5f * spotAngle * Mathf.Deg2Rad), 0.0f); float innerDot = Mathf.Max(Mathf.Cos(0.5f * spotAngle * Mathf.Deg2Rad * innerSpotPercent01), 0.0f); @@ -487,7 +530,7 @@ static public float ShapeAttenuationSpotConeLight(Vector3 forward, Vector3 wo, f /// } /// /// - static public float ShapeAttenuationSpotBoxLight(Vector3 forward, Vector3 wo) + public static float ShapeAttenuationSpotBoxLight(Vector3 forward, Vector3 wo) { return Mathf.Max(Mathf.Sign(Vector3.Dot(forward, wo)), 0.0f); } @@ -534,7 +577,7 @@ static public float ShapeAttenuationSpotBoxLight(Vector3 forward, Vector3 wo) /// } /// /// - static public float ShapeAttenuationSpotPyramidLight(Vector3 forward, Vector3 wo) + public static float ShapeAttenuationSpotPyramidLight(Vector3 forward, Vector3 wo) { return ShapeAttenuationSpotBoxLight(forward, wo); } @@ -692,7 +735,7 @@ static float ShapeAttenuateForwardLight(Vector3 forward, Vector3 wo) /// } /// /// - static public float ShapeAttenuationAreaRectangleLight(Vector3 forward, Vector3 wo) + public static float ShapeAttenuationAreaRectangleLight(Vector3 forward, Vector3 wo) { return ShapeAttenuateForwardLight(forward, wo); } @@ -739,7 +782,7 @@ static public float ShapeAttenuationAreaRectangleLight(Vector3 forward, Vector3 /// } /// /// - static public float ShapeAttenuationAreaDiscLight(Vector3 forward, Vector3 wo) + public static float ShapeAttenuationAreaDiscLight(Vector3 forward, Vector3 wo) { return ShapeAttenuateForwardLight(forward, wo); } @@ -875,9 +918,10 @@ static Vector3 WorldToViewportDistance(Camera cam, Vector3 positionWS) /// /// Camera /// true if cloud occlusion is requested - static public bool IsCloudLayerOpacityNeeded(Camera cam) + public static bool IsCloudLayerOpacityNeeded(Camera cam) { - if (Instance.IsEmpty()) + var instance = Instance; + if (instance.IsEmpty()) return false; #if UNITY_EDITOR @@ -895,9 +939,9 @@ static public bool IsCloudLayerOpacityNeeded(Camera cam) } #endif - foreach (LensFlareCompInfo info in Instance.Data) + foreach (LensFlareCompInfo info in instance.m_Data) { - if (info == null || info.comp == null) + if (info.comp == null) continue; LensFlareComponentSRP comp = info.comp; @@ -1080,7 +1124,7 @@ out LensFlareComponentSRP[] prefabStageLensFlares static bool DoComponent( bool occlusionOnly, - LensFlareCompInfo info, + in LensFlareCompInfo info, Camera cam, Vector3 cameraPositionWS, float actualWidth, @@ -1116,7 +1160,7 @@ out float distanceAttenuation flareIntensity = 0f; distanceAttenuation = 1f; - if (info == null || info.comp == null) + if (info.comp == null) return false; LensFlareComponentSRP comp = info.comp; @@ -1251,7 +1295,7 @@ out float distanceAttenuation /// Unused /// Unused /// Sun Occlusion Texture from VolumetricCloud on HDRP or null - static public void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex, + public static void ComputeOcclusion(Material lensFlareShader, Camera cam, XRPass xr, int xrIndex, float actualWidth, float actualHeight, bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative, Vector3 cameraPositionWS, @@ -1284,11 +1328,13 @@ out LensFlareComponentSRP[] prefabStageLensFlares float aspect = actualWidth / actualHeight; - foreach (LensFlareCompInfo info in m_Data) + int shaderPassLensFlareOcclusion = lensFlareShader.FindPass("LensFlareOcclusion"); + var instance = Instance; + foreach (LensFlareCompInfo info in instance.m_Data) { bool okComp = DoComponent( true, - info, + in info, cam, cameraPositionWS, actualWidth, @@ -1333,8 +1379,8 @@ out float distanceAttenuation cmd.SetGlobalInt(_FlareOcclusionPermutation, convInt); } - float globalCos0 = Mathf.Cos(0.0f); - float globalSin0 = Mathf.Sin(0.0f); + const float globalCos0 = 1f; //Mathf.Cos(0.0f); + const float globalSin0 = 0f; //Mathf.Sin(0.0f); float position = 0.0f; @@ -1351,24 +1397,24 @@ out float distanceAttenuation Rect rect; if (taaEnabled) - rect = new Rect() { x = info.index, y = frameIdx + mergeNeeded, width = 1, height = 1 }; + rect = new Rect() { x = info.index, y = instance.frameIdx + mergeNeeded, width = 1, height = 1 }; else rect = new Rect() { x = info.index, y = 0, width = 1, height = 1 }; cmd.SetViewport(rect); - Blitter.DrawQuad(cmd, lensFlareShader, lensFlareShader.FindPass("LensFlareOcclusion")); + Blitter.DrawQuad(cmd, lensFlareShader, shaderPassLensFlareOcclusion); } // Clear the remaining buffer if not TAA the whole OcclusionRT is already cleared if (taaEnabled) { CoreUtils.SetRenderTarget(cmd, occlusionRT, depthSlice: xrIndex); - cmd.SetViewport(new Rect() { x = m_Data.Count, y = 0, width = (maxLensFlareWithOcclusion - m_Data.Count), height = (maxLensFlareWithOcclusionTemporalSample + mergeNeeded) }); + cmd.SetViewport(new Rect() { x = instance.m_Data.Count, y = 0, width = (maxLensFlareWithOcclusion - instance.m_Data.Count), height = (maxLensFlareWithOcclusionTemporalSample + mergeNeeded) }); cmd.ClearRenderTarget(false, true, Color.black); } - ++frameIdx; - frameIdx %= maxLensFlareWithOcclusionTemporalSample; + ++instance.frameIdx; + instance.frameIdx %= maxLensFlareWithOcclusionTemporalSample; xr.StartSinglePass(cmd); } @@ -1750,7 +1796,7 @@ static void ProcessLensFlareSRPElements(ref LensFlareDataElementSRP[] elements, /// Source Render Target which contains the Color Buffer /// Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP /// Debug View which setup black background to see only lens flare - static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex, + public static void DoLensFlareDataDrivenCommon(Material lensFlareShader, Camera cam, Rect viewport, XRPass xr, int xrIndex, float actualWidth, float actualHeight, bool usePanini, float paniniDistance, float paniniCropToFit, bool isCameraRelative, @@ -1837,11 +1883,12 @@ out LensFlareComponentSRP[] prefabStageLensFlares cmd.SetViewport(viewport); float aspect = actualWidth / actualHeight; - foreach (LensFlareCompInfo info in m_Data) + var instance = Instance; + foreach (LensFlareCompInfo info in instance.m_Data) { bool okComp = DoComponent( false, - info, + in info, cam, cameraPositionWS, actualWidth, @@ -1944,7 +1991,7 @@ out float distanceAttenuation /// UnsafeCommandBuffer /// Result RT for the lens flare Screen Space /// Information if we are in debug mode or not - static public void DoLensFlareScreenSpaceCommon( + public static void DoLensFlareScreenSpaceCommon( Material lensFlareShader, Camera cam, float actualWidth, @@ -2009,7 +2056,7 @@ static public void DoLensFlareScreenSpaceCommon( /// Command Buffer /// Result RT for the lens flare Screen Space /// Information if we are in debug mode or not - static public void DoLensFlareScreenSpaceCommon( + public static void DoLensFlareScreenSpaceCommon( Material lensFlareShader, Camera cam, float actualWidth, @@ -2243,5 +2290,17 @@ static Vector2 Panini_Generic_Inv(Vector2 projPos, float d) } #endregion + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void ResetStaticsOnLoad() + { + Dispose(); + + maxLensFlareWithOcclusion = k_DefaultMaxLensFlareWithOcclusion; + maxLensFlareWithOcclusionTemporalSample = k_DefaultMaxFlareWithOcclusionTemporalSample; + mergeNeeded = k_DefaultMergeNeeded; + } +#endif } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareComponentSRP.cs b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareComponentSRP.cs index 6913fe88bb7..9cda8d45a27 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareComponentSRP.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareComponentSRP.cs @@ -34,10 +34,7 @@ enum Version /// public LensFlareDataSRP lensFlareData { - get - { - return m_LensFlareData; - } + get => m_LensFlareData; set { m_LensFlareData = value; @@ -130,7 +127,7 @@ public LensFlareDataSRP lensFlareData /// Our default celestial body will have an angular radius of 3.3 degrees. This is an arbitrary number, but must be kept constant /// so the occlusion radius for direct lights is consistent regardless of near / far clip plane configuration. - private static float sCelestialAngularRadius = 3.3f * Mathf.PI / 180.0f; + const float sCelestialAngularRadius = 3.3f * Mathf.PI / 180.0f; /// /// OcclusionRemapCurve allow the occlusion [from 0 to 1] to be remap with any desired shape. @@ -154,13 +151,13 @@ public float celestialProjectedOcclusionRadius(Camera mainCam) return occlusionRadius * projectedRadius; } +#if UNITY_EDITOR void Awake() { -#if UNITY_EDITOR if (!lensFlareData) lensFlareData = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.core/Runtime/RenderPipelineResources/Default Lens Flare (SRP).asset"); -#endif } +#endif /// /// Add or remove the lens flare to the queue of PostProcess @@ -202,7 +199,7 @@ private void OnDestroy() } #if UNITY_EDITOR - private float sDebugClippingSafePercentage = 0.9f; //for debug gizmo, only push 90% further so we avoid clipping of debug lines. + private const float k_DebugClippingSafePercentage = 0.9f; //for debug gizmo, only push 90% further so we avoid clipping of debug lines. void OnDrawGizmosSelected() { Camera mainCam = Camera.current; @@ -213,7 +210,7 @@ void OnDrawGizmosSelected() Light light = GetComponent(); if (light != null && light.type == LightType.Directional) { - positionWS = -transform.forward * (mainCam.farClipPlane * sDebugClippingSafePercentage) + mainCam.transform.position; + positionWS = -transform.forward * (mainCam.farClipPlane * k_DebugClippingSafePercentage) + mainCam.transform.position; adjustedOcclusionRadius = celestialProjectedOcclusionRadius(mainCam); } else From a63a02948cb72b01d6f02d1db5225abd8028d1dd Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 21 Apr 2026 06:24:44 +0000 Subject: [PATCH 18/56] GFXLIGHT-2027 : Fix high flickering on SSR with TAA --- .../Runtime/Camera/CameraHistory.cs | 34 ++++-- .../Textures/BufferedRTHandleSystem.cs | 109 ++++++++++++------ .../Runtime/FrameData/UniversalCameraData.cs | 4 + .../Runtime/History/ColorHistory.cs | 61 +++++++++- .../Runtime/History/DepthHistory.cs | 82 ++++++++++++- .../Runtime/MotionVectors.cs | 1 + .../ScreenSpaceReflectionPass.cs | 13 ++- .../Runtime/UniversalRendererRenderGraph.cs | 29 ++--- .../ComputeScreenSpaceReflection.hlsl | 15 ++- .../SampleScreenSpaceReflection.hlsl | 14 ++- 10 files changed, 285 insertions(+), 77 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs index d21c93177cd..dc14a67f948 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs @@ -103,7 +103,7 @@ public interface ICameraHistoryReadAccess public abstract class CameraHistoryItem : ContextItem { // BufferedRTHandleSystem of the owning camera. - private BufferedRTHandleSystem m_owner = null; + private BufferedRTHandleSystem m_Owner = null; // Unique id for this type (derived) given by the owning camera. private uint m_TypeId = uint.MaxValue; @@ -117,7 +117,7 @@ public abstract class CameraHistoryItem : ContextItem /// Unique id given to this class type by the owning camera. public virtual void OnCreate(BufferedRTHandleSystem owner, uint typeId) { - m_owner = owner; + m_Owner = owner; m_TypeId = typeId; } @@ -126,7 +126,7 @@ public virtual void OnCreate(BufferedRTHandleSystem owner, uint typeId) /// /// The owning camera RTHandle storage for the history textures. /// - protected BufferedRTHandleSystem storage => m_owner; + protected BufferedRTHandleSystem storage => m_Owner; /// /// Creates unique ids for the RTHandle storage. @@ -173,7 +173,7 @@ protected RTHandle AllocHistoryFrameRT(int id, int count, RenderTextureDescriptor d = desc; // Simplified for typical history textures: // No shadows, no mipmaps, no aniso. - m_owner.AllocBuffer(id, count, ref desc, filterMode, TextureWrapMode.Clamp, false, 0, 0, name); + m_Owner.AllocBuffer(id, count, ref desc, filterMode, TextureWrapMode.Clamp, false, 0, 0, name); return GetCurrentFrameRT(0); } @@ -183,7 +183,7 @@ protected RTHandle AllocHistoryFrameRT(int id, int count, /// Id for the history RTHandle storage. protected void ReleaseHistoryFrameRT(int id) { - m_owner.ReleaseBuffer(id); + m_Owner.ReleaseBuffer(id); } /// @@ -193,7 +193,7 @@ protected void ReleaseHistoryFrameRT(int id) /// The RTHandle from previous frame. protected RTHandle GetPreviousFrameRT(int id) { - return m_owner.GetFrameRT(id, 1); + return m_Owner.GetFrameRT(id, 1); } /// @@ -203,7 +203,27 @@ protected RTHandle GetPreviousFrameRT(int id) /// The RTHandle of the current frame. protected RTHandle GetCurrentFrameRT(int id) { - return m_owner.GetFrameRT(id, 0); + return m_Owner.GetFrameRT(id, 0); + } + + /// + /// Returns the id stable index from the previous frame. + /// + /// Id for the history RTHandle storage. + /// The stable index from previous frame. + protected int GetPreviousFrameRTStableIndex(int id) + { + return m_Owner.GetFrameRTStableIndex(id, 1); + } + + /// + /// Returns the id stable index of the current frame. + /// + /// Id for the history RTHandle storage. + /// The stable index of the current frame. + protected int GetCurrentFrameRTStableIndex(int id) + { + return m_Owner.GetFrameRTStableIndex(id, 0); } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs index 5b454ebc084..1443018d71a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs @@ -47,7 +47,13 @@ namespace UnityEngine.Rendering /// public class BufferedRTHandleSystem : IDisposable { - Dictionary m_RTHandles = new Dictionary(); + struct RTEntry + { + public RTHandle handle; + public int stableIndex; + } + + Dictionary m_RTEntries = new Dictionary(); RTHandleSystem m_RTHandleSystem = new RTHandleSystem(); bool m_DisposedValue = false; @@ -65,6 +71,21 @@ public class BufferedRTHandleSystem : IDisposable /// public RTHandleProperties rtHandleProperties { get { return m_RTHandleSystem.rtHandleProperties; } } + bool TryGetFrameRenderTarget(int bufferId, int frameIndex, out RTEntry rt) + { + if (!m_RTEntries.ContainsKey(bufferId)) + { + rt.handle = null; + rt.stableIndex = -1; + return false; + } + + Assert.IsTrue(frameIndex >= 0 && frameIndex < m_RTEntries[bufferId].Length); + + rt = m_RTEntries[bufferId][frameIndex]; + return true; + } + /// /// Return the frame RT or null. /// @@ -73,12 +94,25 @@ public class BufferedRTHandleSystem : IDisposable /// The frame RT or null when the was not previously allocated (). public RTHandle GetFrameRT(int bufferId, int frameIndex) { - if (!m_RTHandles.ContainsKey(bufferId)) - return null; + if (TryGetFrameRenderTarget(bufferId, frameIndex, out var rt)) + return rt.handle; + + return null; + } - Assert.IsTrue(frameIndex >= 0 && frameIndex < m_RTHandles[bufferId].Length); + /// + /// Return the frame RT's stable index or -1. + /// A stable index can be used to index into an array of user data assigned to each RT. + /// + /// Defines the buffer to use. + /// Defines which frame to access within the buffer. + /// The frame RT stable index or -1 when the was not previously allocated (). + public int GetFrameRTStableIndex(int bufferId, int frameIndex) + { + if (TryGetFrameRenderTarget(bufferId, frameIndex, out var rt)) + return rt.stableIndex; - return m_RTHandles[bufferId][frameIndex]; + return -1; } /// @@ -88,11 +122,11 @@ public RTHandle GetFrameRT(int bufferId, int frameIndex) public void ClearBuffers(CommandBuffer cmd) { - foreach (var rtHandle in m_RTHandles) + foreach (var rtEntry in m_RTEntries) { - for (int i = 0; i < rtHandle.Value.Length; ++i) + for (int i = 0; i < rtEntry.Value.Length; ++i) { - CoreUtils.SetRenderTarget(cmd, rtHandle.Value[i], clearFlag: ClearFlag.Color, clearColor: Color.black); + CoreUtils.SetRenderTarget(cmd, rtEntry.Value[i].handle, clearFlag: ClearFlag.Color, clearColor: Color.black); } } } @@ -113,17 +147,19 @@ int bufferCount // If the caller provides a value of zero, they're likely doing something unintentional in the calling code. Debug.Assert(bufferCount > 0); - var buffer = new RTHandle[bufferCount]; - m_RTHandles.Add(bufferId, buffer); + var buffer = new RTEntry[bufferCount]; + m_RTEntries.Add(bufferId, buffer); // First is autoresized - buffer[0] = allocator(m_RTHandleSystem, 0); + buffer[0].handle = allocator(m_RTHandleSystem, 0); + buffer[0].stableIndex = 0; // Other are resized on demand for (int i = 1, c = buffer.Length; i < c; ++i) { - buffer[i] = allocator(m_RTHandleSystem, i); - m_RTHandleSystem.SwitchResizeMode(buffer[i], RTHandleSystem.ResizeMode.OnDemand); + buffer[i].handle = allocator(m_RTHandleSystem, i); + buffer[i].stableIndex = i; + m_RTHandleSystem.SwitchResizeMode(buffer[i].handle, RTHandleSystem.ResizeMode.OnDemand); } } @@ -153,21 +189,22 @@ public void AllocBuffer(int bufferId, int bufferCount, // If the caller provides a value of zero, they're likely doing something unintentional in the calling code. Debug.Assert(bufferCount > 0); - var buffer = new RTHandle[bufferCount]; - m_RTHandles.Add(bufferId, buffer); + var buffer = new RTEntry[bufferCount]; + m_RTEntries.Add(bufferId, buffer); RTHandleAllocInfo allocInfo = RTHandles.GetRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name); allocInfo.isShadowMap = isShadowMap; // First is autoresized - buffer[0] = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); + buffer[0].handle = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); + buffer[0].stableIndex = 0; // Other are resized on demand for (int i = 1, c = buffer.Length; i < c; ++i) { - buffer[i] = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); - m_RTHandleSystem.SwitchResizeMode(buffer[i], RTHandleSystem.ResizeMode.OnDemand); + buffer[i].handle = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); + buffer[i].stableIndex = i; } } @@ -177,13 +214,13 @@ public void AllocBuffer(int bufferId, int bufferCount, /// Id of the buffer that needs to be released. public void ReleaseBuffer(int bufferId) { - if (m_RTHandles.TryGetValue(bufferId, out var buffers)) + if (m_RTEntries.TryGetValue(bufferId, out var buffers)) { foreach (var rt in buffers) - m_RTHandleSystem.Release(rt); + m_RTHandleSystem.Release(rt.handle); } - m_RTHandles.Remove(bufferId); + m_RTEntries.Remove(bufferId); } /// @@ -214,10 +251,10 @@ public void ResetReferenceSize(int width, int height) /// The num of frames allocated public int GetNumFramesAllocated(int bufferId) { - if (!m_RTHandles.ContainsKey(bufferId)) + if (!m_RTEntries.ContainsKey(bufferId)) return 0; - return m_RTHandles[bufferId].Length; + return m_RTEntries[bufferId].Length; } /// @@ -233,23 +270,23 @@ public Vector2 CalculateRatioAgainstMaxSize(int width, int height) void Swap() { - foreach (var item in m_RTHandles) + foreach (var rtEntry in m_RTEntries) { // Do not index out of bounds... - if (item.Value.Length > 1) + if (rtEntry.Value.Length > 1) { - var nextFirst = item.Value[item.Value.Length - 1]; - for (int i = item.Value.Length - 1; i > 0; --i) - item.Value[i] = item.Value[i - 1]; - item.Value[0] = nextFirst; + var nextFirst = rtEntry.Value[rtEntry.Value.Length - 1]; + for (int i = rtEntry.Value.Length - 1; i > 0; --i) + rtEntry.Value[i] = rtEntry.Value[i - 1]; + rtEntry.Value[0] = nextFirst; // First is autoresize, other are on demand - m_RTHandleSystem.SwitchResizeMode(item.Value[0], RTHandleSystem.ResizeMode.Auto); - m_RTHandleSystem.SwitchResizeMode(item.Value[1], RTHandleSystem.ResizeMode.OnDemand); + m_RTHandleSystem.SwitchResizeMode(rtEntry.Value[0].handle, RTHandleSystem.ResizeMode.Auto); + m_RTHandleSystem.SwitchResizeMode(rtEntry.Value[1].handle, RTHandleSystem.ResizeMode.OnDemand); } else { - m_RTHandleSystem.SwitchResizeMode(item.Value[0], RTHandleSystem.ResizeMode.Auto); + m_RTHandleSystem.SwitchResizeMode(rtEntry.Value[0].handle, RTHandleSystem.ResizeMode.Auto); } } } @@ -282,14 +319,14 @@ public void Dispose() /// public void ReleaseAll() { - foreach (var item in m_RTHandles) + foreach (var rtEntry in m_RTEntries) { - for (int i = 0, c = item.Value.Length; i < c; ++i) + for (int i = 0, c = rtEntry.Value.Length; i < c; ++i) { - m_RTHandleSystem.Release(item.Value[i]); + m_RTHandleSystem.Release(rtEntry.Value[i].handle); } } - m_RTHandles.Clear(); + m_RTEntries.Clear(); } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs index da6b2a9da47..dd10be4aa33 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs @@ -127,6 +127,10 @@ internal Matrix4x4 GetGPUProjectionMatrix(bool renderIntoTexture, int viewIndex return GL.GetGPUProjectionMatrix(GetProjectionMatrix(viewIndex), renderIntoTexture); } + // The jitter matrix is Matrix4x4.Translate(offsetX, offsetY, 0), so the offsets sit in column 3. + // Jitter values are in NDC space (-1 to 1). + internal Vector2 jitter => new Vector2(m_JitterMatrix.m03, m_JitterMatrix.m13); + /// /// The camera component. /// diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/History/ColorHistory.cs b/Packages/com.unity.render-pipelines.universal/Runtime/History/ColorHistory.cs index 0bc07262e41..a2c89c15d9b 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/History/ColorHistory.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/History/ColorHistory.cs @@ -12,7 +12,9 @@ namespace UnityEngine.Rendering.Universal /// public abstract class ColorHistory : CameraHistoryItem { + // Currently we are storing up to 2, one for each eye in the case of XR stereo rendering private int[] m_Ids = new int[2]; + /// /// The names to use for history items. /// @@ -23,6 +25,10 @@ public abstract class ColorHistory : CameraHistoryItem }; private RenderTextureDescriptor m_Descriptor; private Hash128 m_DescKey; + // Store one jitter offset per eye per history RT. Currently the jitter offset + // is the same for both eyes, but first of all this could change, but mostly + // it's because eye jitters could be updated at different times. + private Vector2[] m_JitterOffsets = new Vector2[2*2]; /// public override void OnCreate(BufferedRTHandleSystem owner, uint typeId) @@ -30,6 +36,7 @@ public override void OnCreate(BufferedRTHandleSystem owner, uint typeId) base.OnCreate(owner, typeId); m_Ids[0] = MakeId(0); m_Ids[1] = MakeId(1); + Array.Fill(m_JitterOffsets, Vector2.zero); } /// @@ -60,6 +67,41 @@ public RTHandle GetPreviousTexture(int eyeIndex = 0) return GetPreviousFrameRT(m_Ids[eyeIndex]); } + /// + /// Get the current history jitter value. + /// Current history might not be valid yet. It is valid only after executing the producing render pass. + /// + /// Eye index, typically XRPass.multipassId. + /// The jitter value in NDC space [-1,1]. + public Vector2 GetCurrentJitter(int eyeIndex = 0) + { + if ((uint)eyeIndex >= m_Ids.Length) + return Vector2.zero; + + int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex < 0) + return Vector2.zero; + + return m_JitterOffsets[stableIndex + 2 * eyeIndex]; + } + + /// + /// Get the previous history jitter value. + /// + /// Eye index, typically XRPass.multipassId. + /// The jitter value in NDC space [-1,1]. + public Vector2 GetPreviousJitter(int eyeIndex = 0) + { + if ((uint)eyeIndex >= m_Ids.Length) + return Vector2.zero; + + int stableIndex = GetPreviousFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex < 0) + return Vector2.zero; + + return m_JitterOffsets[stableIndex + 2 * eyeIndex]; + } + private bool IsAllocated() { return GetCurrentTexture() != null; @@ -103,8 +145,25 @@ internal RenderTextureDescriptor GetHistoryDescriptor(ref RenderTextureDescripto } // Return true if the RTHandles were reallocated. - internal bool Update(UniversalCameraData cameraData, ref RenderTextureDescriptor cameraDesc, bool xrMultipassEnabled = false) + internal bool Update(UniversalCameraData cameraData, bool xrMultipassEnabled = false) { +#if ENABLE_VR && ENABLE_XR_MODULE + int eyeIndex = (cameraData.xr.enabled && !cameraData.xr.singlePassEnabled) ? cameraData.xr.multipassId : 0; +#else + const int eyeIndex = 0; +#endif + Debug.Assert(eyeIndex < m_JitterOffsets.Length); + int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex >= 0) + { + // Update the current jitter value for the current eye. Note that we could handle the case where + // this is the first time or if we reallocate the buffers except there's no clear definition of + // what we should use for a sensible previous jitter value in that case. So might just leave it as is. + m_JitterOffsets[stableIndex + 2 * eyeIndex] = cameraData.jitter; + } + + ref RenderTextureDescriptor cameraDesc = ref cameraData.cameraTargetDescriptor; + if (cameraDesc.width > 0 && cameraDesc.height > 0 && cameraDesc.graphicsFormat != GraphicsFormat.None) { var historyDesc = GetHistoryDescriptor(ref cameraDesc); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/History/DepthHistory.cs b/Packages/com.unity.render-pipelines.universal/Runtime/History/DepthHistory.cs index 840d3076767..38df8a56bc1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/History/DepthHistory.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/History/DepthHistory.cs @@ -13,7 +13,9 @@ namespace UnityEngine.Rendering.Universal /// public abstract class DepthHistory : CameraHistoryItem { + // Currently we are storing up to 2, one for each eye in the case of XR stereo rendering private int[] m_Ids = new int[2]; + /// /// The names to use for history items. /// @@ -24,6 +26,10 @@ public abstract class DepthHistory : CameraHistoryItem }; private RenderTextureDescriptor m_Descriptor; private Hash128 m_DescKey; + // Store one jitter offset per eye per history RT. Currently the jitter offset + // is the same for both eyes, but first of all this could change, but mostly + // it's because eye jitters could be updated at different times. + private Vector2[] m_JitterOffsets = new Vector2[2*2]; /// public override void OnCreate(BufferedRTHandleSystem owner, uint typeId) @@ -31,6 +37,7 @@ public override void OnCreate(BufferedRTHandleSystem owner, uint typeId) base.OnCreate(owner, typeId); m_Ids[0] = MakeId(0); m_Ids[1] = MakeId(1); + Array.Fill(m_JitterOffsets, Vector2.zero); } /// @@ -60,6 +67,41 @@ public RTHandle GetPreviousTexture(int eyeIndex = 0) return GetPreviousFrameRT(m_Ids[eyeIndex]); } + /// + /// Get the current history jitter value. + /// Current history might not be valid yet. It is valid only after executing the producing render pass. + /// + /// Eye index, typically XRPass.multipassId. + /// The jitter value in NDC space [-1,1]. + public Vector2 GetCurrentJitter(int eyeIndex = 0) + { + if ((uint)eyeIndex >= m_Ids.Length) + return Vector2.zero; + + int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex < 0) + return Vector2.zero; + + return m_JitterOffsets[stableIndex + 2 * eyeIndex]; + } + + /// + /// Get the previous history jitter value. + /// + /// Eye index, typically XRPass.multipassId. + /// The jitter value in NDC space [-1,1]. + public Vector2 GetPreviousJitter(int eyeIndex = 0) + { + if ((uint)eyeIndex >= m_Ids.Length) + return Vector2.zero; + + int stableIndex = GetPreviousFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex < 0) + return Vector2.zero; + + return m_JitterOffsets[stableIndex + 2 * eyeIndex]; + } + private bool IsAllocated() { return GetCurrentTexture() != null; @@ -102,8 +144,46 @@ internal RenderTextureDescriptor GetHistoryDescriptor(ref RenderTextureDescripto } // Return true if the RTHandles were reallocated. - internal bool Update(ref RenderTextureDescriptor cameraDesc, bool xrMultipassEnabled) + internal bool Update(UniversalCameraData cameraData, bool xrMultipassEnabled, in RenderTextureDescriptor? cameraDescOverride = null) { +#if ENABLE_VR && ENABLE_XR_MODULE + int eyeIndex = (cameraData.xr.enabled && !cameraData.xr.singlePassEnabled) ? cameraData.xr.multipassId : 0; +#else + const int eyeIndex = 0; +#endif + Debug.Assert(eyeIndex < m_JitterOffsets.Length); + int stableIndex = GetCurrentFrameRTStableIndex(m_Ids[eyeIndex]); + if (stableIndex >= 0) + { + // Update the current jitter value for the current eye. Note that we could handle the case where + // this is the first time or if we reallocate the buffers except there's no clear definition of + // what we should use for a sensible previous jitter value in that case. So might just leave it as is. + m_JitterOffsets[stableIndex + 2 * eyeIndex] = cameraData.jitter; + } + + RenderTextureDescriptor cameraDesc; + if (cameraDescOverride.HasValue) + { + cameraDesc = cameraDescOverride.Value; + } + else + { + cameraDesc = cameraData.cameraTargetDescriptor; + + // On GLES we don't support sampling the MSAA targets, so if auto depth resolve is not available, the only thing that works is rendering to a color target. + // This has been the behavior from at least 6.0. However, it results in the format mostly being color on the different graphics APIs, even when + // it could be a depth format if MSAA sampling for depth is allowed. + if (RenderingUtils.MultisampleDepthResolveSupported()) + { + cameraDesc.graphicsFormat = GraphicsFormat.None; + } + else + { + cameraDesc.graphicsFormat = GraphicsFormat.R32_SFloat; + cameraDesc.depthStencilFormat = GraphicsFormat.None; + } + } + if (cameraDesc.width > 0 && cameraDesc.height > 0 && (cameraDesc.depthStencilFormat != GraphicsFormat.None || cameraDesc.graphicsFormat != GraphicsFormat.None) ) { var historyDesc = GetHistoryDescriptor(ref cameraDesc); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/MotionVectors.cs b/Packages/com.unity.render-pipelines.universal/Runtime/MotionVectors.cs index 6d0cb9a9382..b83aee5d3ed 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/MotionVectors.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/MotionVectors.cs @@ -131,6 +131,7 @@ internal Vector3 previousPreviousWorldSpaceCameraPos { get => m_previousPreviousWorldSpaceCameraPos; } + #endregion public void Reset() diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/ScreenSpaceReflectionRendererFeature/ScreenSpaceReflectionPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/ScreenSpaceReflectionRendererFeature/ScreenSpaceReflectionPass.cs index 10e8274165b..147420ec4cf 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/ScreenSpaceReflectionRendererFeature/ScreenSpaceReflectionPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/ScreenSpaceReflectionRendererFeature/ScreenSpaceReflectionPass.cs @@ -76,6 +76,7 @@ internal static class ShaderConstants internal static readonly int _HitRefinementSteps = Shader.PropertyToID("_HitRefinementSteps"); internal static readonly int _DepthPyramidMipLevelOffsets = Shader.PropertyToID("_DepthPyramidMipLevelOffsets"); internal static readonly int _SourceSize = Shader.PropertyToID("_SourceSize"); + internal static readonly int _CameraDeltaJitterOffset = Shader.PropertyToID("_CameraDeltaJitterOffset"); } // Private Variables @@ -182,6 +183,9 @@ private class ScreenSpaceReflectionPassData // MipInfo for HiZ marching. internal PackedMipChainInfo mipsInfo; + // Various camera settings + internal Vector2 previousJitter; + // Required textures. internal TextureHandle cameraColor; // Camera target texture. internal TextureHandle cameraDepth; // Camera depth target texture. @@ -268,6 +272,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // Set required pass data. passData.cameraData = cameraData; + passData.previousJitter = Vector2.zero; passData.afterOpaque = m_AfterOpaque; passData.linearMarching = settings.ShouldUseLinearMarching(); passData.useGaussianBlur = settings.ShouldUseGaussianBlurRoughness(); @@ -364,6 +369,8 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer { passData.lastFrameCameraDepth = renderGraph.ImportTexture(depthHistoryTexture); builder.UseTexture(passData.lastFrameCameraDepth); + + passData.previousJitter = history.GetPreviousJitter(multipassId); } } } @@ -526,6 +533,10 @@ static void SetupKeywordsAndParameters(ref ScreenSpaceReflectionPassData data) data.cameraInverseViewProjections[eyeIndex] = data.cameraViewProjections[eyeIndex].inverse; } + // Send the difference between the current and previous jitter values so we can reproject taking jittering + // into account. Divide by 2 because the jittering values are in NDC space (-1 to 1) and we need them in texture space (0 to 1). + // We use the current jitter from the cameraData as the one in the history is not yet up to date because the depth history update is done later on in the frame. + data.material.SetVector(ShaderConstants._CameraDeltaJitterOffset, (Vector4)(cameraData.jitter - data.previousJitter) * 0.5f); data.material.SetMatrixArray(ShaderConstants._CameraProjections, data.cameraProjections); data.material.SetMatrixArray(ShaderConstants._CameraInverseProjections, data.cameraInverseProjections); data.material.SetMatrixArray(ShaderConstants._CameraViews, data.cameraViews); @@ -698,7 +709,7 @@ private static void RenderDepthHistory(RenderGraph renderGraph, UniversalCameraD tempColorDepthDesc.graphicsFormat = GraphicsFormat.R32_SFloat; tempColorDepthDesc.depthStencilFormat = GraphicsFormat.None; - depthHistory.Update(ref tempColorDepthDesc, xrMultipassEnabled); + depthHistory.Update(cameraData, xrMultipassEnabled, tempColorDepthDesc); if (depthHistory.GetCurrentTexture(multipassId) != null) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs index a0ae55d1cda..6acfe8b073d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs @@ -540,7 +540,7 @@ private void RenderRawColorDepthHistory(RenderGraph renderGraph, UniversalCamera var colorHistory = history.GetHistoryForWrite(); if (colorHistory != null) { - colorHistory.Update(cameraData, ref cameraData.cameraTargetDescriptor, xrMultipassEnabled); + colorHistory.Update(cameraData, xrMultipassEnabled); if (colorHistory.GetCurrentTexture(multipassId) != null) { var colorHistoryTarget = renderGraph.ImportTexture(colorHistory.GetCurrentTexture(multipassId)); @@ -555,22 +555,7 @@ private void RenderRawColorDepthHistory(RenderGraph renderGraph, UniversalCamera var depthHistory = history.GetHistoryForWrite(); if (depthHistory != null) { - var tempColorDepthDesc = cameraData.cameraTargetDescriptor; - - //On GLES we don't support sampling the MSAA targets, so if auto depth resolve is not available, the only thing that works is rendering to a color target. - //This has been the behavior from at least 6.0. However, it results in the format mostly being color on the different graphics APIs, even when - //it could be a depth format if MSAA sampling for depht is allowed. - if (RenderingUtils.MultisampleDepthResolveSupported()) - { - tempColorDepthDesc.graphicsFormat = GraphicsFormat.None; - } - else - { - tempColorDepthDesc.graphicsFormat = GraphicsFormat.R32_SFloat; - tempColorDepthDesc.depthStencilFormat = GraphicsFormat.None; - } - - depthHistory.Update(ref tempColorDepthDesc, xrMultipassEnabled); + depthHistory.Update(cameraData, xrMultipassEnabled); if (depthHistory.GetCurrentTexture(multipassId) != null) { @@ -603,7 +588,7 @@ private void RenderBeforeTransparentsColorHistory(RenderGraph renderGraph, Unive var colorHistory = history.GetHistoryForWrite(); if (colorHistory != null) { - colorHistory.Update(cameraData, ref cameraData.cameraTargetDescriptor, xrMultipassEnabled); + colorHistory.Update(cameraData, xrMultipassEnabled); if (colorHistory.GetCurrentTexture(multipassId) != null) { var colorHistoryTarget = renderGraph.ImportTexture(colorHistory.GetCurrentTexture(multipassId)); @@ -1469,7 +1454,7 @@ private void OnAfterRendering(RenderGraph renderGraph, bool applyPostProcessing) } RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent.AfterRendering); - + // We can explicitely render the overlay UI from URP when HDR output is not enabled. // SupportedRenderingFeatures.active.rendersUIOverlay should also be set to true. bool shouldRenderUI = cameraData.rendersOverlayUI && cameraData.isLastBaseCamera; @@ -1478,10 +1463,10 @@ private void OnAfterRendering(RenderGraph renderGraph, bool applyPostProcessing) { var color = resourceData.activeColorTexture; var cameraDepth = resourceData.cameraDepth; - + TextureHandle depth; - if (cameraDepth.IsValid() && SystemInfo.supportsBackbufferInMultipleRenderTargets) + if (cameraDepth.IsValid() && SystemInfo.supportsBackbufferInMultipleRenderTargets) { var backbufferInfo = renderGraph.GetRenderTargetInfo(resourceData.backBufferDepth); var cameraDepthDesc = renderGraph.GetTextureDesc(in cameraDepth); @@ -1490,7 +1475,7 @@ private void OnAfterRendering(RenderGraph renderGraph, bool applyPostProcessing) && backbufferInfo.width == cameraDepthDesc.width && backbufferInfo.height == cameraDepthDesc.height && backbufferInfo.volumeDepth == cameraDepthDesc.slices; - // Using the cameraDepth avoids switching the depth target, that would break the native render pass. + // Using the cameraDepth avoids switching the depth target, that would break the native render pass. depth = (matchingDimensions) ? cameraDepth : resourceData.activeDepthTexture; } else diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl index 299a22ca5d3..a1b77574043 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl @@ -30,7 +30,7 @@ float4x4 _CameraInverseViewProjections[2]; float4x4 _CameraProjections[2]; float4x4 _CameraInverseProjections[2]; float4x4 _CameraViews[2]; - +float4 _CameraDeltaJitterOffset; float4 _SourceSize; TYPED_TEXTURE2D_X(float, _DepthPyramid); @@ -425,8 +425,11 @@ float4 ComputeSSR(Varyings input) : SV_Target { #ifdef _USE_MOTION_VECTORS // Reproject position - const float2 downsampledScreenSize = screenSizeWithInverse.zw * _Downsample; rayHitPosNDC.xy -= SampleMotionVector(rayHitPosNDC.xy); + // Compensate for jittering + rayHitPosNDC.xy -= _CameraDeltaJitterOffset; + + const float2 downsampledScreenSize = screenSizeWithInverse.zw * _Downsample; const int2 topLeftReprojectedPixelPos = int2(rayHitPosNDC.xy * downsampledScreenSize - 0.5); // Manually apply bilinear filter at the reprojected position @@ -458,8 +461,12 @@ float4 ComputeSSR(Varyings input) : SV_Target weightSum += weight; } } - // If we got no valid samples, just return the existing framebuffer color. - if (weightSum == 0) + // If we got no valid samples, just return the existing framebuffer color. The sample is invalid if the total + // sum of weights is 0 but due to precision issues if the total weight is extremely low (which can lead + // to wrongly high color values, once divided by it) we check if the total weight is under an epsilon + // value instead. + const float k_MinimumWeight = 1e-3; + if (weightSum < k_MinimumWeight) return float4(SAMPLE_TEXTURE2D_X_LOD(_CameraColorTexture, sampler_CameraColorTexture, positionNDC, 0).rgb, 0); else hitColor /= weightSum; diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SampleScreenSpaceReflection.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SampleScreenSpaceReflection.hlsl index 2e4c33a0399..2637d67648b 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SampleScreenSpaceReflection.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SampleScreenSpaceReflection.hlsl @@ -10,16 +10,20 @@ half4 SampleScreenSpaceReflection(float2 normalizedScreenSpaceUV, float3 positio { float2 uv = UnityStereoTransformScreenSpaceTex(normalizedScreenSpaceUV); - // Map roughness to mip level to get blur. - float mipLevel = GetSSRMipLevelFromPerceptualRoughness(positionWS, perceptualRoughness); - float4 reflColor = SAMPLE_TEXTURE2D_X_LOD(_ScreenSpaceReflectionTexture, sampler_TrilinearClamp, uv, mipLevel); - // Fade out reflections for pixels that have smoothness below our minimum. float perceptualSmoothness = PerceptualRoughnessToPerceptualSmoothness(perceptualRoughness); float fadeStart = _ScreenSpaceReflectionParam.y; float fadeEnd = _ScreenSpaceReflectionParam.z; float fade = smoothstep(fadeStart, fadeEnd, perceptualSmoothness); - reflColor.a *= fade; + float4 reflColor = float4(0,0,0,0); + + if (fade > 1e-3) + { + // Map roughness to mip level to get blur. + float mipLevel = GetSSRMipLevelFromPerceptualRoughness(positionWS, perceptualRoughness); + reflColor = SAMPLE_TEXTURE2D_X_LOD(_ScreenSpaceReflectionTexture, sampler_TrilinearClamp, uv, mipLevel); + reflColor.a *= fade; + } return reflColor; } From c11f4aa76c4642b1ca0700336b5bd692d6785d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Chapelain?= Date: Tue, 21 Apr 2026 06:24:54 +0000 Subject: [PATCH 19/56] [SRP] Fix scene view camera transform on HD Template --- .../Assets/SampleSceneAssets/Scripts.meta | 8 +++++ .../Scripts/SyncSceneViewCamera.cs | 36 +++++++++++++++++++ .../Scripts/SyncSceneViewCamera.cs.meta | 2 ++ .../Assets/Scenes/SampleScene.unity | 4 +-- 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts.meta create mode 100644 Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs create mode 100644 Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs.meta diff --git a/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts.meta b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts.meta new file mode 100644 index 00000000000..f2545478761 --- /dev/null +++ b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da02876f45ef820418fdd9d8ddeafe4e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs new file mode 100644 index 00000000000..f86133e1ff9 --- /dev/null +++ b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs @@ -0,0 +1,36 @@ +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; + +[ExecuteInEditMode] +public class SyncSceneViewCamera : MonoBehaviour +{ + + void Awake() + { + AlignCamera(transform); + } + + + private static void AlignCamera(Transform target) + { +#if UNITY_EDITOR + SceneView view = SceneView.lastActiveSceneView; + if (view == null) + return; + + Camera sceneCam = view.camera; + if(sceneCam == null) + return; + + sceneCam.transform.position = target.position; + sceneCam.transform.rotation = target.rotation; + view.AlignViewToObject(sceneCam.transform); +#endif + } + +} + + + diff --git a/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs.meta b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs.meta new file mode 100644 index 00000000000..5c548f0c16c --- /dev/null +++ b/Templates/com.unity.template-hd/Assets/SampleSceneAssets/Scripts/SyncSceneViewCamera.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 33cbf51b7c38ecd459275e3343806869 \ No newline at end of file diff --git a/Templates/com.unity.template-hd/Assets/Scenes/SampleScene.unity b/Templates/com.unity.template-hd/Assets/Scenes/SampleScene.unity index 9de4cd9e31f..42787f98e82 100644 --- a/Templates/com.unity.template-hd/Assets/Scenes/SampleScene.unity +++ b/Templates/com.unity.template-hd/Assets/Scenes/SampleScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c0b5e40027fb0cd1b7805c747fd135c78fab393f0bb17a240c359dbc73a16d02 -size 1194973 +oid sha256:47a3fa3655180a244087dd69952351654f1220f0e52b2534dbfe91d60feb9873 +size 1195726 From 4257930b6cad877d77da977f84b96960b00c088e Mon Sep 17 00:00:00 2001 From: Ashley Kitchen Date: Tue, 21 Apr 2026 06:24:59 +0000 Subject: [PATCH 20/56] [URP][Shader Graph] Add stereo instancing support to custom UITK shaders written in ShaderGraph --- .../Editor/ShaderGraph/Includes/UITKPass.hlsl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl index 03f675a2799..918543b6372 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl @@ -16,6 +16,9 @@ PackedVaryings uie_custom_vert(Attributes input) uieInput.circle = input.uv6; uieInput.textureId = input.uv7.x; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_TRANSFER_INSTANCE_ID(input, uieInput); + v2f uieOutput = uie_std_vert(uieInput); Varyings varyings = (Varyings)0; @@ -32,6 +35,9 @@ PackedVaryings uie_custom_vert(Attributes input) varyings.texCoord3 = float4(uieOutput.textCoreLoc.x, uieOutput.textCoreLoc.y, input.uv0.z, input.uv0.w); // Layout uv in z, w varyings.texCoord4 = uieOutput.circle; + UNITY_TRANSFER_INSTANCE_ID(input, varyings); + UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(uieOutput, varyings); + PackedVaryings packedOutput = PackVaryings(varyings); return packedOutput; } From 6333b245ff900ecaf950dfe969b280e3e695d565 Mon Sep 17 00:00:00 2001 From: April Roszkowski Date: Tue, 21 Apr 2026 06:25:04 +0000 Subject: [PATCH 21/56] [UUM-139845] Restore virtual texturing keyword permutation logic --- .../Generation/Processors/GenerationUtils.cs | 59 +++++++++++++++---- .../Editor/Generation/Processors/Generator.cs | 9 +-- .../Processors/GeneratorDerivativeUtils.cs | 9 +-- .../VirtualTexturingFeedbackUtils.cs} | 1 - .../VirtualTexturingFeedbackUtils.cs.meta} | 0 5 files changed, 52 insertions(+), 26 deletions(-) rename Packages/com.unity.shadergraph/Editor/{Data/Nodes/Input/Texture/TextureStackNode.cs => Generation/Processors/VirtualTexturingFeedbackUtils.cs} (99%) rename Packages/com.unity.shadergraph/Editor/{Data/Nodes/Input/Texture/TextureStackNode.cs.meta => Generation/Processors/VirtualTexturingFeedbackUtils.cs.meta} (100%) diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Processors/GenerationUtils.cs b/Packages/com.unity.shadergraph/Editor/Generation/Processors/GenerationUtils.cs index a15d510e9fa..99130f9fd40 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Processors/GenerationUtils.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Processors/GenerationUtils.cs @@ -485,11 +485,10 @@ internal static void GetUpstreamNodesForShaderPass(AbstractMaterialNode outputNo NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, outputNode, NodeUtils.IncludeSelf.Include); } - internal static void GetActiveFieldsAndPermutationsForNodes(PassDescriptor pass, - KeywordCollector keywordCollector, List vertexNodes, List pixelNodes, - bool[] texCoordNeedsDerivs, - List[] vertexNodePermutations, List[] pixelNodePermutations, - ActiveFields activeFields, out ShaderGraphRequirementsPerKeyword graphRequirements) + internal static void GetActiveFieldsAndRequirements(PassDescriptor pass, + List vertexNodes, List pixelNodes, + bool[] texCoordNeedsDerivs, ActiveFields activeFields, + out ShaderGraphRequirementsPerKeyword graphRequirements) { // Initialize requirements ShaderGraphRequirementsPerKeyword pixelRequirements = new ShaderGraphRequirementsPerKeyword(); @@ -516,6 +515,47 @@ internal static void GetActiveFieldsAndPermutationsForNodes(PassDescriptor pass, graphRequirements.UnionWith(vertexRequirements); } + internal static List[] GetPermutationsForNodes(KeywordCollector keywordCollector, List nodes) + { + List[] permutationsPerNode = new List[nodes.Count]; + + // Map each node to its index for perf + Dictionary nodeToIndex = new(nodes.Count); + for (int i = 0; i < nodes.Count; ++i) + nodeToIndex[nodes[i]] = i; + + // Evaluate all Keyword permutations + for (int i = 0; i < keywordCollector.permutations.Count; i++) + { + // Get active nodes for this permutation + var localNodes = Pool.HashSetPool.Get(); + localNodes.EnsureCapacity(nodes.Count); + + foreach (var node in nodes) + { + if (node is BlockNode) + { + NodeUtils.DepthFirstCollectNodesFromNode(localNodes, node, NodeUtils.IncludeSelf.Include, + keywordCollector.permutations[i]); + } + } + + // Track each node in this permutation + foreach (AbstractMaterialNode localNode in localNodes) + { + int nodeIndex = nodeToIndex[localNode]; + + if (permutationsPerNode[nodeIndex] == null) + permutationsPerNode[nodeIndex] = new List(); + permutationsPerNode[nodeIndex].Add(i); + } + + Pool.HashSetPool.Release(localNodes); + } + + return permutationsPerNode; + } + static ConditionalField[] GetConditionalFieldsFromVertexRequirements(ShaderGraphRequirements requirements) { return new ConditionalField[] @@ -1090,7 +1130,7 @@ internal static void GenerateSurfaceDescriptionStruct(ShaderStringBuilder surfac internal static void GenerateSurfaceDescriptionFunction( List nodes, - List[] keywordPermutationsPerNode, + Lazy[]> keywordPermutationsPerNode, AbstractMaterialNode rootNode, GraphData graph, ShaderStringBuilder surfaceDescriptionFunction, @@ -1123,7 +1163,7 @@ internal static void GenerateSurfaceDescriptionFunction( surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName); for (int i = 0; i < nodes.Count; i++) { - GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, surfaceDescriptionFunction, + GenerateDescriptionForNode(nodes[i], null, functionRegistry, surfaceDescriptionFunction, shaderProperties, shaderKeywords, graph, mode); } @@ -1138,7 +1178,7 @@ internal static void GenerateSurfaceDescriptionFunction( { VirtualTexturingFeedbackUtils.GenerateVirtualTextureFeedback( nodes, - keywordPermutationsPerNode, + keywordPermutationsPerNode.Value, surfaceDescriptionFunction, shaderKeywords); } @@ -1272,7 +1312,6 @@ internal static void GenerateVertexDescriptionFunction( GenerationMode mode, AbstractMaterialNode rootNode, List nodes, - List[] keywordPermutationsPerNode, List slots, string graphInputStructName = "VertexDescriptionInputs", string functionName = "PopulateVertexData", @@ -1297,7 +1336,7 @@ internal static void GenerateVertexDescriptionFunction( Profiler.BeginSample("GenerateNodeDescriptions"); for (int i = 0; i < nodes.Count; i++) { - GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, builder, + GenerateDescriptionForNode(nodes[i], null, functionRegistry, builder, shaderProperties, shaderKeywords, graph, mode); } diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs b/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs index 166bc223f47..e55b8064d90 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Processors/Generator.cs @@ -699,13 +699,11 @@ void ProcessStackForPass(ContextData contextData, BlockFieldDescriptor[] passBlo customInterpSubGen.ProcessExistingStackData(vertexNodes, vertexSlots, pixelNodes, activeFields.baseInstance); // Track permutation indices for all nodes - List[] vertexNodePermutations = new List[vertexNodes.Count]; - List[] pixelNodePermutations = new List[pixelNodes.Count]; + Lazy[]> pixelNodePermutations = new(() => GenerationUtils.GetPermutationsForNodes(keywordCollector, pixelNodes)); // Get active fields from upstream Node requirements ShaderGraphRequirementsPerKeyword graphRequirements; - // using(s_profileGetActiveFieldsFromUpstreamNodes.Auto()) - GenerationUtils.GetActiveFieldsAndPermutationsForNodes(pass, keywordCollector, vertexNodes, pixelNodes, new bool[ShaderGeneratorNames.UVCount], vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); + GenerationUtils.GetActiveFieldsAndRequirements(pass, vertexNodes, pixelNodes, new bool[ShaderGeneratorNames.UVCount], activeFields, out graphRequirements); // Moved this up so that we can reuse the information to figure out which struct Descriptors // should be populated by custom interpolators. @@ -971,7 +969,6 @@ void ProcessStackForPass(ContextData contextData, BlockFieldDescriptor[] passBlo m_Mode, m_OutputNode, vertexNodes, - vertexNodePermutations, vertexSlots, vertexGraphInputName, vertexGraphFunctionName, @@ -1203,8 +1200,6 @@ void ProcessStackForPass(ContextData contextData, BlockFieldDescriptor[] passBlo keywordCollector, vertexNodes, pixelNodes, - vertexNodePermutations, - pixelNodePermutations, originalPassStructs, pass.analyticDerivativesApplyEmulate, m_HumanReadable, diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Processors/GeneratorDerivativeUtils.cs b/Packages/com.unity.shadergraph/Editor/Generation/Processors/GeneratorDerivativeUtils.cs index 45de603629f..c3734d48aa7 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Processors/GeneratorDerivativeUtils.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Processors/GeneratorDerivativeUtils.cs @@ -160,8 +160,6 @@ internal static void ParseAndModifyForAnalyticDerivatives( KeywordCollector keywordCollector, List vertexNodes, List pixelNodes, - List[] vertexNodePermutations, - List[] pixelNodePermutations, List originalPassStructs, bool applyEmulatedDerivatives, bool isHumanReadable, @@ -234,8 +232,7 @@ internal static void ParseAndModifyForAnalyticDerivatives( { // use the new uv derivative needs to produce text ShaderGraphRequirementsPerKeyword graphRequirements = new ShaderGraphRequirementsPerKeyword(); - GenerationUtils.GetActiveFieldsAndPermutationsForNodes(pass, keywordCollector, vertexNodes, pixelNodes, adjustedUvDerivs, - vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); + GenerationUtils.GetActiveFieldsAndRequirements(pass, vertexNodes, pixelNodes, adjustedUvDerivs, activeFields, out graphRequirements); ShaderStringBuilder interpolatorBuilder = new ShaderStringBuilder(); ShaderStringBuilder passStructBuilder = new ShaderStringBuilder(); @@ -265,8 +262,6 @@ internal static void ApplyAnalyticDerivatives( KeywordCollector keywordCollector, List vertexNodes, List pixelNodes, - List[] vertexNodePermutations, - List[] pixelNodePermutations, List originalPassStructs, bool applyEmulatedDerivatives, bool isHumanReadable, @@ -289,8 +284,6 @@ internal static void ApplyAnalyticDerivatives( keywordCollector, vertexNodes, pixelNodes, - vertexNodePermutations, - pixelNodePermutations, originalPassStructs, pass.analyticDerivativesApplyEmulate, isHumanReadable, diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Texture/TextureStackNode.cs b/Packages/com.unity.shadergraph/Editor/Generation/Processors/VirtualTexturingFeedbackUtils.cs similarity index 99% rename from Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Texture/TextureStackNode.cs rename to Packages/com.unity.shadergraph/Editor/Generation/Processors/VirtualTexturingFeedbackUtils.cs index 6e1b69183b3..56f0d72d7a2 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Texture/TextureStackNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Processors/VirtualTexturingFeedbackUtils.cs @@ -12,7 +12,6 @@ namespace UnityEditor.ShaderGraph { - // TODO: rename this file to VirtualTexturingFeedbackUtils static class VirtualTexturingFeedbackUtils { // TODO: could get rid of this if we could run a codegen prepass (with proper keyword #ifdef) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Texture/TextureStackNode.cs.meta b/Packages/com.unity.shadergraph/Editor/Generation/Processors/VirtualTexturingFeedbackUtils.cs.meta similarity index 100% rename from Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Texture/TextureStackNode.cs.meta rename to Packages/com.unity.shadergraph/Editor/Generation/Processors/VirtualTexturingFeedbackUtils.cs.meta From 62d3946fe1e8d195833025d2cac362263490b5d9 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 21 Apr 2026 06:25:06 +0000 Subject: [PATCH 22/56] GFXLIGHT-1911 : Gradient environment support for Surface Cache --- .../SurfaceCache/SurfaceCacheWorld.cs | 10 +++++ .../PathTracing/Environment/CubemapRender.cs | 33 +++++++++++--- .../SurfaceCacheGIRendererFeature.cs | 5 ++- .../SurfaceCacheWorldAdapter.cs | 44 ++++++++++++------- 4 files changed, 67 insertions(+), 25 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs index 0729668bdb2..fbd35215f6a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/SurfaceCache/SurfaceCacheWorld.cs @@ -351,6 +351,16 @@ public void SetEnvironmentColor(Color color) _cubemapRender.SetColor(color); } + public void SetEnvironmentGradientColors(Color skyColor, Color equatorColor, Color groundColor) + { + _cubemapRender.SetFaceColor(CubemapFace.PositiveX, equatorColor); + _cubemapRender.SetFaceColor(CubemapFace.NegativeX, equatorColor); + _cubemapRender.SetFaceColor(CubemapFace.PositiveY, skyColor); + _cubemapRender.SetFaceColor(CubemapFace.NegativeY, groundColor); + _cubemapRender.SetFaceColor(CubemapFace.PositiveZ, equatorColor); + _cubemapRender.SetFaceColor(CubemapFace.NegativeZ, equatorColor); + } + public void SetEnvironmentIntensityMultiplier(float multiplier) { _environmentIntensityMultiplier = multiplier; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Environment/CubemapRender.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Environment/CubemapRender.cs index 0d111d6a488..7444d187f20 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Environment/CubemapRender.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Environment/CubemapRender.cs @@ -20,7 +20,15 @@ internal enum Mode private Material _material; private Shader _lastUsedShader; private LocalKeyword? _noSunKeyword; - private Color _color = Color.black; + private Color[] _faceColors = new Color[6] + { + Color.black, + Color.black, + Color.black, + Color.black, + Color.black, + Color.black + }; private readonly Mesh _skyboxMesh; private readonly Mesh _sixFaceSkyboxMesh; private RenderTexture _cubemap; @@ -59,7 +67,15 @@ public void SetMaterial(Material mat) public void SetColor(Color color) { - _color = color; + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + _faceColors[faceIndex] = color; + } + } + + public void SetFaceColor(CubemapFace face, Color color) + { + _faceColors[(int)face] = color; } public void SetMode(Mode mode) @@ -83,7 +99,10 @@ public void Update(CommandBuffer cmd, Light sun, int resolution, out bool viewAn int newHash = ((int)_mode) + 1; if (_mode == Mode.Color) { - newHash ^= HashCode.Combine(_color.r, _color.g, _color.b); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + newHash = HashCode.Combine(newHash, _faceColors[faceIndex].r, _faceColors[faceIndex].g, _faceColors[faceIndex].b); + } if (newHash != _hash) RenderWithColor(cmd); @@ -92,13 +111,13 @@ public void Update(CommandBuffer cmd, Light sun, int resolution, out bool viewAn { if (_material) { - newHash ^= _material.ComputeCRC(); + newHash = HashCode.Combine(newHash, _material.ComputeCRC()); if (sun != null) { var color = LightColorInRenderingSpace(sun); var dir = -sun.GetComponent().forward; - newHash ^= HashCode.Combine(color.r, color.g, color.b); - newHash ^= HashCode.Combine(dir.x, dir.y, dir.z); + newHash = HashCode.Combine(newHash, color.r, color.g, color.b); + newHash = HashCode.Combine(newHash, dir.x, dir.y, dir.z); } if (newHash != _hash) @@ -136,7 +155,7 @@ private void RenderWithColor(CommandBuffer cmd) { cmd.SetRenderTarget(new RenderTargetIdentifier(_cubemap, 0, (CubemapFace) faceIndex)); cmd.SetViewport(new Rect(0, 0, 1, 1)); - cmd.ClearRenderTarget(false, true, _color); + cmd.ClearRenderTarget(false, true, _faceColors[faceIndex]); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs index 7e109b4baf7..76e7ed0d5ef 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheGIRendererFeature.cs @@ -661,7 +661,10 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // RenderSettings.ambientIntensity is used directly as a linear value for Surface Cache, which is not currently // the case for the standard ambient probe lighting, which is assumed to be in gamma space and then converted to // linear space. We will make this more coherent for the ambient probe in the future. - _worldAdapter.Update(_sceneTracker, RenderSettings.ambientMode, RenderSettings.skybox, RenderSettings.ambientSkyColor, RenderSettings.ambientIntensity, _world); + // Similarly, the ambient colors are all defined in sRGB space and must be converted to linear. + _worldAdapter.Update(_sceneTracker, RenderSettings.ambientMode, RenderSettings.skybox, + RenderSettings.ambientSkyColor.linear, RenderSettings.ambientEquatorColor.linear, RenderSettings.ambientGroundColor.linear, + RenderSettings.ambientIntensity, _world); using (var builder = renderGraph.AddUnsafePass("Surface Cache World Update", out WorldUpdatePassData passData)) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs index 6d0736c20cf..e30afc604e1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/SurfaceCacheGIRendererFeature/SurfaceCacheWorldAdapter.cs @@ -54,7 +54,9 @@ public SurfaceCacheWorldAdapter(SurfaceCacheWorld world, Material fallbackMateri _entityIDToWorldMaterialDescriptors.Add(fallbackMaterial.GetEntityId(), _fallbackMaterialDescriptor); } - internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, Material skyboxMaterial, Color ambientSkycolor, float envIntensityMultiplier, SurfaceCacheWorld world) + internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, Material skyboxMaterial, + Color ambientSkycolor, Color ambientEquatorColor, Color ambientGroundColor, float envIntensityMultiplier, + SurfaceCacheWorld world) { const bool filterBakedLights = true; var changes = sceneTracker.GetChanges(filterBakedLights); @@ -79,23 +81,31 @@ internal void Update(SceneUpdatesTracker sceneTracker, AmbientMode ambientMode, const bool multiplyPunctualLightIntensityByPI = false; UpdateLights(world, changes.addedLights, changes.removedLights, changes.changedLights, multiplyPunctualLightIntensityByPI); - if (ambientMode == AmbientMode.Skybox) + switch (ambientMode) { - world.SetEnvironmentMode(CubemapRender.Mode.Material); - world.SetEnvironmentMaterial(skyboxMaterial); - world.SetEnvironmentIntensityMultiplier(envIntensityMultiplier); - } - else if (ambientMode == AmbientMode.Flat) - { - world.SetEnvironmentMode(CubemapRender.Mode.Color); - world.SetEnvironmentColor(ambientSkycolor); - world.SetEnvironmentIntensityMultiplier(1.0f); - } - else - { - world.SetEnvironmentMode(CubemapRender.Mode.Color); - world.SetEnvironmentColor(Color.black); - world.SetEnvironmentIntensityMultiplier(1.0f); + case AmbientMode.Skybox: + world.SetEnvironmentMode(CubemapRender.Mode.Material); + world.SetEnvironmentMaterial(skyboxMaterial); + world.SetEnvironmentIntensityMultiplier(envIntensityMultiplier); + break; + + case AmbientMode.Flat: + world.SetEnvironmentMode(CubemapRender.Mode.Color); + world.SetEnvironmentColor(ambientSkycolor); + world.SetEnvironmentIntensityMultiplier(1.0f); + break; + + case AmbientMode.Trilight: + world.SetEnvironmentMode(CubemapRender.Mode.Color); + world.SetEnvironmentGradientColors(ambientSkycolor, ambientEquatorColor, ambientGroundColor); + world.SetEnvironmentIntensityMultiplier(1.0f); + break; + + default: + world.SetEnvironmentMode(CubemapRender.Mode.Color); + world.SetEnvironmentColor(Color.black); + world.SetEnvironmentIntensityMultiplier(1.0f); + break; } } From 0d75c2f98140c31281e1f5298195388d34f50f41 Mon Sep 17 00:00:00 2001 From: Ludovic Theobald Date: Tue, 21 Apr 2026 10:21:08 +0000 Subject: [PATCH 23/56] [VFX New Compiler] GPU Expressions in blocks --- .../CodeGeneration/ComputeShaderWriter.cs | 2 +- .../CodeGeneration/RenderingShaderWriter.cs | 2 +- .../Compiler/Passes/DataLayoutPass.cs | 10 +- .../Passes/TemplateCodeGenerationPass.cs | 23 +- .../Data/Description/UnorderedData.cs | 21 +- .../Editor/GraphCommon/Graph/TaskGraph.cs | 30 +-- .../GraphCommon/Graph/TaskGraphCache.cs | 2 + .../NewCompiler/Tasks/PlaceholderTask.cs | 8 +- .../Editor/NewCompiler/VfxGraphCompiler.cs | 4 +- .../VfxIntermediateGraphBuilder.cs | 176 +++++++--------- .../Editor/NewCompiler/VfxSubTaskBuilder.cs | 197 ++++++++++++++++++ .../NewCompiler/VfxSubTaskBuilder.cs.meta | 3 + .../Shaders/Temp/Data/ByteAddressBuffer.hlsl | 31 +-- 13 files changed, 361 insertions(+), 148 deletions(-) create mode 100644 Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs create mode 100644 Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs.meta diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/ComputeShaderWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/ComputeShaderWriter.cs index 383c5cc3f34..960f6660953 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/ComputeShaderWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/ComputeShaderWriter.cs @@ -10,7 +10,7 @@ public override void Begin(string name) Pragma("kernel CSMain"); Pragma("only_renderers d3d11 glcore gles3 metal vulkan xboxone xboxone xboxseries playstation ps5 switch webgpu"); - //Pragma("enable_d3d11_debug_symbols"); + //Pragma("enable_debug_symbols"); NewLine(); } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/RenderingShaderWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/RenderingShaderWriter.cs index e815c2ebfdc..38c90bc1bca 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/RenderingShaderWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/CodeGeneration/RenderingShaderWriter.cs @@ -47,7 +47,7 @@ public void PassBegin(string name) OpenBlock(); WriteLine("HLSLPROGRAM"); Pragma("target 5.0"); - Pragma("enable_d3d11_debug_symbols"); + Pragma("enable_debug_symbols"); Pragma("vertex VFXVertex"); Pragma("fragment VFXFragment"); diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs index d1177f7cc5e..78863fffaf8 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/DataLayoutPass.cs @@ -70,8 +70,8 @@ List GenerateChildLayouts(IEnumerable children class ConcreteLayout { - public int Size { get; private set; } - private Dictionary m_ValueDataOffsets = new(); + int Size { get; set; } + Dictionary m_ValueDataOffsets = new(); public ConcreteLayout(ValueData valueData) { @@ -128,7 +128,7 @@ public static ConcreteLayout FromUnordered(List children) return layout; } - public void AppendSubLayout(ConcreteLayout subLayout) + void AppendSubLayout(ConcreteLayout subLayout) { int currentSize = Size; foreach (var kvp in subLayout.m_ValueDataOffsets) @@ -138,7 +138,7 @@ public void AppendSubLayout(ConcreteLayout subLayout) Size += subLayout.Size; } - public void PadSize() + void PadSize() { if(Size % 4 != 0) { @@ -146,7 +146,7 @@ public void PadSize() } } - public string DebugString() + public override string ToString() { string result = $"ConcreteLayout(Size: {Size}, ValueDataOffsets: {{"; foreach (var kvp in m_ValueDataOffsets) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/TemplateCodeGenerationPass.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/TemplateCodeGenerationPass.cs index a958b33d936..e4e69524b43 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/TemplateCodeGenerationPass.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Compiler/Passes/TemplateCodeGenerationPass.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Collections.Generic; using UnityEditor; +using UnityEditor.VFX; using UnityEngine; namespace Unity.GraphCommon.LowLevel.Editor @@ -21,14 +22,6 @@ public TemplateCodeGenerationPass(DataDescriptionWriterRegistry dataWriter) m_DataWriter = dataWriter; } - static readonly MethodInfo k_CreateComputeShaderAsset = typeof(ShaderUtil).GetMethod("CreateComputeShaderAsset", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null); - ComputeShader CreateComputeShaderAsset(string sourceCode) - { - if (k_CreateComputeShaderAsset == null) - throw new NullReferenceException(); - return (ComputeShader)k_CreateComputeShaderAsset.Invoke(null, new object[] {sourceCode}); - } - public bool Execute(ref CompilationContext context) { var generatedCodeContainer = context.data.GetOrCreate(); @@ -52,7 +45,7 @@ public bool Execute(ref CompilationContext context) { sourceCode = GenerateTemplatedTaskSourceCode_Compute(taskNode, context); - var computeShader = CreateComputeShaderAsset(sourceCode); + var computeShader = ShaderUtil.CreateComputeShaderAsset(sourceCode); computeShader.name = templatedTask.TemplateName; var task = new GpuKernelTask(computeShader, 0); context.graph.SetTask(taskNode.Id, task); @@ -114,6 +107,8 @@ string GenerateTemplatedTaskSourceCode_Compute(TaskNode taskNode, CompilationCon GenerateDataViews(m_ComputeShaderWriter, taskNode, templatedTask, context); + IncludeCommonLibrary(m_ComputeShaderWriter); + ForwardDeclarations(m_ComputeShaderWriter, templatedTask); IncludeTemplateFile(m_ComputeShaderWriter, templatedTask.TemplateName); @@ -143,6 +138,8 @@ string GenerateTemplatedTaskSourceCode_Rendering(TaskNode taskNode, CompilationC GenerateDataViews(m_RenderingShaderWriter, taskNode, templatedTask, context); + IncludeCommonLibrary(m_RenderingShaderWriter); + ForwardDeclarations(m_RenderingShaderWriter, templatedTask); IncludeTemplateFile(m_RenderingShaderWriter, templatedTask.TemplateName); @@ -319,12 +316,16 @@ void WriteProcessBlocksDeclaration(ShaderWriter shaderWriter, TemplatedTask temp shaderWriter.Write(")"); } - void ForwardDeclarations(ShaderWriter shaderWriter, TemplatedTask templatedTask) + void IncludeCommonLibrary(ShaderWriter shaderWriter) { shaderWriter.NewLine(); shaderWriter.Define("VFX_LOCAL_SPACE", "1"); - shaderWriter.IncludeFile("Packages/com.unity.render-pipelines.universal/Runtime/VFXGraph/Shaders/VFXCommon.hlsl"); + shaderWriter.IncludeFile($"{VFXLibrary.currentSRPBinder.runtimePath}/VFXCommon.hlsl"); shaderWriter.IncludeFile("Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl"); + } + + void ForwardDeclarations(ShaderWriter shaderWriter, TemplatedTask templatedTask) + { WriteProcessBlocksDeclaration(shaderWriter, templatedTask); shaderWriter.Write(";"); shaderWriter.NewLine(); diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs index c16736b3d18..04fa25750bb 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Data/Description/UnorderedData.cs @@ -7,7 +7,8 @@ namespace Unity.GraphCommon.LowLevel.Editor /// /*public*/ class UnorderedData : IDataDescription { - Dictionary m_Datas = new(); + Dictionary m_DataKeyToDataDescriptions = new(); + Dictionary m_DataDescriptionToDataKey = new(); /// /// Adds a data element, providing the data identifier and the data description. @@ -17,24 +18,34 @@ namespace Unity.GraphCommon.LowLevel.Editor /// True if the data element was added, false otherwise (for instance, if it was already present). public bool AddSubdata(IDataKey dataKey, IDataDescription data) { - return m_Datas.TryAdd(dataKey, data); + return m_DataKeyToDataDescriptions.TryAdd(dataKey, data) && m_DataDescriptionToDataKey.TryAdd(data, dataKey); } /// public IDataDescription GetSubdata(IDataKey dataKey) { - return m_Datas.GetValueOrDefault(dataKey); + return m_DataKeyToDataDescriptions.GetValueOrDefault(dataKey); + } + + /// + /// Get the IDataKey associated with the sub data dataDescription. + /// + /// The sub data to query the key from. + /// The IDataKey associated with the sub data dataDescription if it exists, null otherwise. + public IDataKey GetSubDataKey(IDataDescription dataDescription) + { + return m_DataDescriptionToDataKey.GetValueOrDefault(dataDescription); } /// /// Enumerates all the subdata descriptions included in this data description. /// - public IEnumerable SubDataDescriptions => m_Datas.Values; + public IEnumerable SubDataDescriptions => m_DataKeyToDataDescriptions.Values; /// /// Enumerates all the subdata descriptions included in this data description. /// - public IEnumerable> SubDatas => m_Datas; + public IEnumerable> SubDatas => m_DataKeyToDataDescriptions; /// public bool IsCompatible(IDataDescription other) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraph.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraph.cs index f4420518d1d..ef331b326ac 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraph.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraph.cs @@ -290,25 +290,31 @@ public void BindData(TaskNodeId taskNodeId, IDataKey bindingKey, DataViewId data bool usesData = task.GetDataUsage(bindingKey, out DataPathSet readUsage, out DataPathSet writeUsage); if (usesData) { - foreach (var path in readUsage.DataPaths) + if(readUsage != null) { - var currentDataViewId = dataViewId; - foreach (var key in path.PathSequence) + foreach (var path in readUsage.DataPaths) { - currentDataViewId = key != null ? GetSubdata(currentDataViewId, key) : currentDataViewId; - if (!currentDataViewId.IsValid) - break; + var currentDataViewId = dataViewId; + foreach (var key in path.PathSequence) + { + currentDataViewId = key != null ? GetSubdata(currentDataViewId, key) : currentDataViewId; + if (!currentDataViewId.IsValid) + break; + } } } - foreach (var path in writeUsage.DataPaths) + if(writeUsage != null) { - var currentDataViewId = dataViewId; - foreach (var key in path.PathSequence) + foreach (var path in writeUsage.DataPaths) { - currentDataViewId = key != null ? GetSubdata(currentDataViewId, key) : currentDataViewId; - if (!currentDataViewId.IsValid) - break; + var currentDataViewId = dataViewId; + foreach (var key in path.PathSequence) + { + currentDataViewId = key != null ? GetSubdata(currentDataViewId, key) : currentDataViewId; + if (!currentDataViewId.IsValid) + break; + } } } } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraphCache.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraphCache.cs index 805fd51bf39..c1ff9dbd17a 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraphCache.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphCommon/Graph/TaskGraphCache.cs @@ -167,6 +167,7 @@ LinearMultiTree BuildDataNodeToReadDataViews() return BuildDataNodeToDataViews((task, dataBinding) => { bool success = task.GetDataUsage(dataBinding.BindingDataKey, out DataPathSet readUsage, out _); + success &= readUsage != null; return (success, readUsage); }); } @@ -176,6 +177,7 @@ LinearMultiTree BuildDataNodeToWrittenDataViews() return BuildDataNodeToDataViews((task, dataBinding) => { bool success = task.GetDataUsage(dataBinding.BindingDataKey, out _, out DataPathSet writeUsage); + success &= writeUsage != null; return (success, writeUsage); }); } diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Tasks/PlaceholderTask.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Tasks/PlaceholderTask.cs index 683124b7027..273455cfddd 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Tasks/PlaceholderTask.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/Tasks/PlaceholderTask.cs @@ -44,10 +44,12 @@ public bool GetDataUsage(IDataKey dataKey, out DataPathSet readUsage, out DataPa writeUsage = m_BindingToUsage[dataKey].Write; return true; } - - readUsage = null; + // If the data key is not explicitly used, we assume it's read without any specific path (e.g., whole struct) and not written. + // This has no functional impact, it is just to clarify the intent, and help debug visualizers. + readUsage = new DataPathSet(); + readUsage.Add(DataPath.Empty); writeUsage = null; - return false; + return true; } /// diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs index 9f7bd178b57..7e94df76594 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxGraphCompiler.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; using Unity.GraphCommon.LowLevel.Editor; -using UnityEngine; using UnityEngine.VFX; namespace UnityEditor.VFX @@ -37,7 +35,7 @@ public VFXGraphCompiledData.VFXCompileOutput Compile(VFXGraph graph, VFXCompilat return new() { success = false }; } - var intermediateGraph = m_GraphBuilder.BuildGraph(graph); + var intermediateGraph = m_GraphBuilder.BuildGraph(graph, compilationMode); // TODO: setup compilation mode and shader debug symbols var compilationResult = m_GraphCompiler.Compile(intermediateGraph); diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs index 2f1867cac4b..e182156f28c 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxIntermediateGraphBuilder.cs @@ -1,5 +1,5 @@ +using System; using System.Collections.Generic; -using System.Text; using Unity.GraphCommon.LowLevel.Editor; using UnityEngine.VFX; using UnityEngine; @@ -31,10 +31,12 @@ public ParticleSystemBuildInfo(VFXData data) Dictionary m_ParticleSystems = new(); VFXSystemNames m_SystemNames = new(); VFXExpressionGraph m_ExpressionGraph; + VfxSubTaskBuilder m_SubTaskBuilder = new VfxSubTaskBuilder(); + Dictionary m_DeduplicatedExpressionsToDataView = new(); Dictionary> m_GraphValueNameCounts = new(); - public IReadOnlyGraph BuildGraph(VFXGraph graph) + public IReadOnlyGraph BuildGraph(VFXGraph graph, VFXCompilationMode compilationMode) { var intermediateGraph = new TaskGraph(); @@ -83,7 +85,8 @@ public IReadOnlyGraph BuildGraph(VFXGraph graph) } } - m_ExpressionGraph.CompileExpressions(compilableContexts, VFXExpressionContextOption.ConstantFolding); + var expressionGraphOptions = compilationMode == VFXCompilationMode.Runtime ? VFXExpressionContextOption.ConstantFolding : VFXExpressionContextOption.Reduction; + m_ExpressionGraph.CompileExpressions(compilableContexts, expressionGraphOptions); foreach (var spawner in spawners) { @@ -103,6 +106,7 @@ void Clear() m_ParticleSystems.Clear(); m_GraphValueNameCounts.Clear(); m_SystemNames = new VFXSystemNames(); + m_DeduplicatedExpressionsToDataView.Clear(); } void BuildSpawnerSystem(VFXBasicSpawner spawner, TaskGraph intermediateGraph) @@ -205,12 +209,12 @@ void BuildGraphValuesBuffer(TaskGraph intermediateGraph, TaskNodeId systemTask, contextDataViewId = intermediateGraph.GetSubdata(graphValuesBufferViewId, TemplatedTask.ContextDataKey); intermediateGraph.GetSubdata(contextDataViewId, paddingKey); // Force data view to be registered - UnorderedData graphValues = new UnorderedData(); - graphValuesBuffer.AddSubdata(kGraphValuesKey, graphValues); + UnorderedData graphValuesUnordered = new UnorderedData(); + graphValuesBuffer.AddSubdata(kGraphValuesKey, graphValuesUnordered); intermediateGraph.BindData(systemTask, TemplatedTask.GraphValuesBufferKey, graphValuesBufferViewId, BindingUsage.Write); - m_GraphValueNameCounts.Add(graphValuesBuffer, new Dictionary()); + m_GraphValueNameCounts.Add(graphValuesUnordered, new Dictionary()); } void BindContextData(TaskGraph intermediateGraph, TaskNodeId contextTask, DataViewId contextDataViewId) @@ -240,25 +244,43 @@ void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNod { var graphValuesViewId = intermediateGraph.GetSubdata(graphValuesBufferViewId, kGraphValuesKey); var graphValuesUnordered = intermediateGraph.DataViews[graphValuesViewId].DataDescription as UnorderedData; + Debug.Assert(graphValuesUnordered != null); + Debug.Assert(m_GraphValueNameCounts.ContainsKey(graphValuesUnordered)); var gpuMapper = m_ExpressionGraph.BuildGPUMapper(context); - foreach (var expression in gpuMapper.expressions) + var uniformMapper = new VFXUniformMapper(gpuMapper, false, false); + + foreach (var expression in uniformMapper.textures) { var expressionDataViewId = AddExpressionRecursively(intermediateGraph, expression); - if (!VFXExpression.IsUniform(expression.valueType)) - { - string bindingName = gpuMapper.GetData(expression)[0].fullName; - IDataKey bindingKey = new NameDataKey(bindingName); - intermediateGraph.BindData(contextTask, bindingKey, expressionDataViewId, BindingUsage.Read); - } - else - { - if(expression.IsAny(VFXExpression.Flags.NotCompilableOnCPU)) - continue; + string bindingName = uniformMapper.GetName(expression); + IDataKey bindingKey = new NameDataKey(bindingName); + intermediateGraph.BindData(contextTask, bindingKey, expressionDataViewId, BindingUsage.Read); + } + foreach (var expression in uniformMapper.buffers) + { + var expressionDataViewId = AddExpressionRecursively(intermediateGraph, expression); + string bindingName = uniformMapper.GetName(expression); + IDataKey bindingKey = new NameDataKey(bindingName); + intermediateGraph.BindData(contextTask, bindingKey, expressionDataViewId, BindingUsage.Read); + } + + foreach (var expression in uniformMapper.uniforms) + { + var expressionDataViewId = AddExpressionRecursively(intermediateGraph, expression); + if(expression.Is(VFXExpression.Flags.Constant)) + continue; + if(expression.IsAny(VFXExpression.Flags.NotCompilableOnCPU)) + continue; + Debug.Assert(VFXExpression.IsUniform(expression.valueType)); - Debug.Assert(m_GraphValueNameCounts.ContainsKey(graphValuesBuffer)); - string bindingName = gpuMapper.GetData(expression)[0].name; - var nameCountMap = m_GraphValueNameCounts[graphValuesBuffer]; + var expressionValue = intermediateGraph.DataViews[expressionDataViewId].DataDescription; + string bindingName = uniformMapper.GetName(expression); + + bool addToGraphValues = graphValuesUnordered.GetSubDataKey(expressionValue) == null; + if (addToGraphValues) + { + var nameCountMap = m_GraphValueNameCounts[graphValuesUnordered]; if (nameCountMap.TryGetValue(bindingName, out uint count)) { nameCountMap[bindingName] = count + 1; @@ -268,19 +290,16 @@ void BindGPUExpressions(TaskGraph intermediateGraph, VFXContext context, TaskNod count = 0; nameCountMap.Add(bindingName, 1); } - string systemUniqueBindingName = $"{bindingName}_{VFXCodeGeneratorHelper.GeneratePrefix(count)}"; IDataKey systemBindingKey = new NameDataKey(systemUniqueBindingName); - IDataKey contextBindingKey = new NameDataKey(gpuMapper.GetData(expression)[0].fullName); - - var expressionValue = intermediateGraph.DataViews[expressionDataViewId].DataDescription; - if(graphValuesUnordered.AddSubdata(systemBindingKey, expressionValue)) - { - intermediateGraph.BindData(systemTask, systemBindingKey, expressionDataViewId, BindingUsage.Read); - } - var subdataViewId = intermediateGraph.GetSubdata(graphValuesViewId, systemBindingKey); - intermediateGraph.BindData(contextTask, contextBindingKey, subdataViewId, BindingUsage.Read); + Debug.Assert(graphValuesUnordered.GetSubdata(systemBindingKey) == null, $"Graph value with name {systemUniqueBindingName} already exists."); + graphValuesUnordered.AddSubdata(systemBindingKey, expressionValue); + intermediateGraph.BindData(systemTask, systemBindingKey, expressionDataViewId, BindingUsage.Read); } + + IDataKey contextBindingKey = new NameDataKey(bindingName); + var subdataViewId = intermediateGraph.GetSubdata(graphValuesViewId, graphValuesUnordered.GetSubDataKey(expressionValue)); + intermediateGraph.BindData(contextTask, contextBindingKey, subdataViewId, BindingUsage.Read); } } @@ -338,7 +357,7 @@ ITask BuildInitializeTask(VFXBasicInitialize initContext) var args = new TemplatedTaskArgs { - Subtasks = GenerateSubtasks(initContext), + Subtasks = m_SubTaskBuilder.GenerateSubtasks(initContext, m_ExpressionGraph), AttributeKeyMappings = new() { @@ -372,9 +391,7 @@ ITask BuildUpdateTask(VFXBasicUpdate updateContext) TemplatedTaskArgs args = new TemplatedTaskArgs { - Subtasks = GenerateSubtasks(updateContext), - - //Expressions = CollectInputExpressions(processor), + Subtasks = m_SubTaskBuilder.GenerateSubtasks(updateContext, m_ExpressionGraph), AttributeKeyMappings = new() { @@ -419,9 +436,7 @@ ITask BuildOutputTask(VFXAbstractParticleOutput outputContext) TemplatedTaskArgs args = new TemplatedTaskArgs { - Subtasks = GenerateSubtasks(outputContext), - - //Expressions = CollectInputExpressions(processor), + Subtasks = m_SubTaskBuilder.GenerateSubtasks(outputContext, m_ExpressionGraph), AttributeKeyMappings = new() { @@ -440,6 +455,11 @@ ITask BuildOutputTask(VFXAbstractParticleOutput outputContext) DataViewId AddExpressionRecursively(TaskGraph taskGraph, VFXExpression expression) { + if (m_DeduplicatedExpressionsToDataView.TryGetValue(expression, out var cachedDataViewId)) + { + return cachedDataViewId; + } + LegacyExpressionTask expressionTask = new LegacyExpressionTask(expression); var taskNodeId = taskGraph.AddTask(expressionTask); @@ -448,71 +468,37 @@ DataViewId AddExpressionRecursively(TaskGraph taskGraph, VFXExpression expressio { taskGraph.BindData(taskNodeId, new IndexDataKey(i), AddExpressionRecursively(taskGraph, parents[i]), BindingUsage.Read); } - - var dataDescription = ValueData.Create(VFXExpression.TypeToType(expression.valueType)); - var dataViewId = taskGraph.AddData(expression.GetType().Name, dataDescription); + var dataDescription = ValueData.Create(VFXValueTypeToType(expression.valueType)); + var dataViewId = taskGraph.AddData($"{expression.GetType().Name}_{taskGraph.DataContainers.Count}", dataDescription); taskGraph.BindData(taskNodeId, LegacyExpressionTask.Value, dataViewId, BindingUsage.Write); + m_DeduplicatedExpressionsToDataView[expression] = dataViewId; return dataViewId; } - List GenerateSubtasks(VFXContext context) + public static Type VFXValueTypeToType(VFXValueType type) { - List subtaskDescriptions = new List(); - var gpuMapper = m_ExpressionGraph.BuildGPUMapper(context); - foreach (var block in context.activeFlattenedChildrenWithImplicit) + switch (type) { - var subTaskDesc = new SubtaskDescription(); - subTaskDesc.Name = block.name; - subTaskDesc.ExpressionBindingKeys = new List(); - - StringBuilder codeBuilder = new StringBuilder(block.source); - - foreach (var parameter in block.parameters) - { - var reduced = m_ExpressionGraph.GPUExpressionsToReduced[parameter.exp]; - if (gpuMapper.GetData(reduced).Count > 0) - { - string bindingName = gpuMapper.GetData(reduced)[0].fullName; - subTaskDesc.ExpressionBindingKeys.Add(new NameDataKey(bindingName)); - - // Generate assignment - if(VFXExpression.IsUniform(reduced.valueType)) - { - string assignment = $"{VFXExpression.TypeToCode(reduced.valueType)} {parameter.name} = {bindingName};\n"; - codeBuilder.Insert(0, assignment); - } - } - } - - Dictionary attributeSets = new Dictionary(); - var attributeSet = new AttributeSet(); - foreach (var attributeInfo in block.attributes) - { - var attribute = VFXAttributesManager.ConvertToNewCompiler(attributeInfo.attrib); - AttributeUsage usage = GetAttributeUsage(attributeInfo.mode); - attributeSet.AddAttribute(attribute, usage); - codeBuilder.Replace(attributeInfo.attrib.name, "attributes." + attributeInfo.attrib.name); - } - if(block.source.Contains("RAND")) - codeBuilder.Insert(0, "uint seed = attributes.seed;"); - - attributeSets.Add(AttributeData.DefaultKey, attributeSet); - - subTaskDesc.Task = new TemplateSubtask(block.name, codeBuilder.ToString(), attributeSets); - - subtaskDescriptions.Add(subTaskDesc); + case VFXValueType.Float: return typeof(float); + case VFXValueType.Float2: return typeof(Vector2); + case VFXValueType.Float3: return typeof(Vector3); + case VFXValueType.Float4: return typeof(Vector4); + case VFXValueType.Int32: return typeof(int); + case VFXValueType.Uint32: return typeof(uint); + case VFXValueType.Texture2D: return typeof(Texture2D); + case VFXValueType.Texture2DArray: return typeof(Texture2DArray); + case VFXValueType.Texture3D: return typeof(Texture3D); + case VFXValueType.TextureCube: return typeof(Cubemap); + case VFXValueType.TextureCubeArray: return typeof(CubemapArray); + case VFXValueType.CameraBuffer: return typeof(CameraBuffer); + case VFXValueType.Matrix4x4: return typeof(Matrix4x4); + case VFXValueType.Mesh: return typeof(Mesh); + case VFXValueType.Curve: return typeof(AnimationCurve); + case VFXValueType.ColorGradient: return typeof(Gradient); + case VFXValueType.Boolean: return typeof(bool); + case VFXValueType.Buffer: return typeof(GraphicsBuffer); } - return subtaskDescriptions; - } - - AttributeUsage GetAttributeUsage(VFXAttributeMode mode) - { - AttributeUsage usage = 0; - if (mode.HasFlag(VFXAttributeMode.Read)) - usage |= AttributeUsage.Read; - if (mode.HasFlag(VFXAttributeMode.Write)) - usage |= AttributeUsage.Write; - return usage; + throw new NotImplementedException(type.ToString()); } } } diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs new file mode 100644 index 00000000000..4ec4d1d1ae6 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs @@ -0,0 +1,197 @@ +using System.Collections.Generic; +using System.Text; +using Unity.GraphCommon.LowLevel.Editor; +using UnityEngine; +using UnityEngine.VFX; + +namespace UnityEditor.VFX +{ + class VfxSubTaskBuilder + { + private ExpressionWriter m_ExpressionWriter = new(); + + public List GenerateSubtasks(VFXContext context, VFXExpressionGraph expressionGraph) + { + List subtaskDescriptions = new List(); + var gpuMapper = expressionGraph.BuildGPUMapper(context); + var uniformMapper = new VFXUniformMapper(gpuMapper, false, false); + m_ExpressionWriter.Initialize(uniformMapper); + + int blockIndex = 0; + foreach (var block in context.activeFlattenedChildrenWithImplicit) + { + m_ExpressionWriter.StartBlock(); + var subTaskDesc = new SubtaskDescription(); + subTaskDesc.Name = block.name; + subTaskDesc.ExpressionBindingKeys = new List(); + + StringBuilder blockCodeBuilder = new StringBuilder(block.source); + StringBuilder expressionCodeBuilder = new StringBuilder(); + + // Patch attributes variable names and register their usage. + Dictionary attributeSets = new Dictionary(); + var attributeSet = new AttributeSet(); + foreach (var attributeInfo in block.attributes) + { + var attribute = VFXAttributesManager.ConvertToNewCompiler(attributeInfo.attrib); + AttributeUsage usage = GetAttributeUsage(attributeInfo.mode); + attributeSet.AddAttribute(attribute, usage); + blockCodeBuilder.Replace(attributeInfo.attrib.name, "attributes." + attributeInfo.attrib.name); + } + + // Generate parameters assignments and register attributes used by expressions + foreach (var parameter in block.parameters) + { + var reduced = gpuMapper.FromNameAndId(parameter.name, blockIndex); + if (!VFXExpression.IsUniform(reduced.valueType)) // TODO: We'll need to handle buffers and textures as block inputs later. + continue; + + string leftHandSide = $"{VFXExpression.TypeToCode(reduced.valueType)} {parameter.name}"; + string rightHandSide; + if (reduced.IsAny(VFXExpression.Flags.NotCompilableOnCPU)) + { + m_ExpressionWriter.WriteExpressionEvaluation(expressionCodeBuilder, reduced); + rightHandSide = m_ExpressionWriter.GetVariableValueString(reduced); + } + else + { + string bindingName = uniformMapper.GetName(reduced); + subTaskDesc.ExpressionBindingKeys.Add(new NameDataKey(bindingName)); + rightHandSide = reduced.Is(VFXExpression.Flags.Constant) ? reduced.GetCodeString(null) : bindingName; + } + expressionCodeBuilder.Append($"{leftHandSide} = {rightHandSide};\n"); + + RegisterBlockAttributesFromExpression(attributeSet, reduced); + } + + // Workaround to handle RAND which implicitly uses the seed attribute + if(block.source.Contains("RAND")) + blockCodeBuilder.Insert(0, "uint seed = attributes.seed;\n"); + + blockCodeBuilder.Insert(0, expressionCodeBuilder.ToString()); + attributeSets.Add(AttributeData.DefaultKey, attributeSet); + subTaskDesc.Task = new TemplateSubtask(block.name, blockCodeBuilder.ToString(), attributeSets); + + subtaskDescriptions.Add(subTaskDesc); + blockIndex++; + } + return subtaskDescriptions; + } + + void RegisterBlockAttributesFromExpression(AttributeSet attributeSet, VFXExpression expression) + { + if (expression is VFXAttributeExpression attributeExpression) + { + attributeSet.AddAttribute(VFXAttributesManager.ConvertToNewCompiler(attributeExpression.attribute), GetAttributeUsage(VFXAttributeMode.Read)); + } + + foreach (var expressionParent in expression.parents) + { + RegisterBlockAttributesFromExpression(attributeSet, expressionParent); + } + } + + AttributeUsage GetAttributeUsage(VFXAttributeMode mode) + { + AttributeUsage usage = 0; + if (mode.HasFlag(VFXAttributeMode.Read)) + usage |= AttributeUsage.Read; + if (mode.HasFlag(VFXAttributeMode.Write)) + usage |= AttributeUsage.Write; + return usage; + } + } + class ExpressionWriter + { + Dictionary m_InputVariableValueStrings = new(); + Dictionary m_GeneratedVariableValueStrings = new(); + uint m_TmpCounter = 0; + + public void Initialize(VFXUniformMapper uniformMapper) + { + m_InputVariableValueStrings.Clear(); + m_GeneratedVariableValueStrings.Clear(); + foreach (var uniform in uniformMapper.uniforms) + { + AddInputVariableValueString(uniform, uniform.Is(VFXExpression.Flags.Constant) ? uniform.GetCodeString(null) : uniformMapper.GetName(uniform)); + } + foreach (var texture in uniformMapper.textures) + { + AddInputVariableValueString(texture, uniformMapper.GetName(texture)); + } + foreach (var buffer in uniformMapper.buffers) + { + AddInputVariableValueString(buffer, uniformMapper.GetName(buffer)); + } + } + + public void StartBlock() + { + m_GeneratedVariableValueStrings.Clear(); + m_TmpCounter = 0; + } + + public string GetVariableValueString(VFXExpression expression) + { + if(m_InputVariableValueStrings.TryGetValue(expression, out string value)) + return value; + if(m_GeneratedVariableValueStrings.TryGetValue(expression, out value)) + return value; + Debug.Assert(false, $"Expression {expression} has not been written yet."); + return null; + } + + public void WriteExpressionEvaluation(StringBuilder codeBuilder, VFXExpression exp) + { + if (HasVariableValueString(exp)) // Expression value is already assigned within the scope. + return; + + string entry; + if (exp.Is(VFXExpression.Flags.Constant)) + entry = exp.GetCodeString(null); // Patch constant directly + else + { + foreach (var parent in exp.parents) + WriteExpressionEvaluation(codeBuilder, parent); + string[] parents = new string[exp.parents.Length]; + for(int i = 0; i < exp.parents.Length; ++i) + { + parents[i] = GetVariableValueString(exp.parents[i]); + } + + string value = exp.GetCodeString(parents); + entry = "tmp_" + VFXCodeGeneratorHelper.GeneratePrefix(m_TmpCounter++); + WriteVariable(codeBuilder, exp.valueType, entry, value); + + codeBuilder.Append('\n'); + } + AddGeneratedVariableValueString(exp, entry); + } + + void WriteVariable(StringBuilder codeBuilder, VFXValueType type, string variableName, string value) + { + if (!VFXExpression.IsTypeValidOnGPU(type)) + return; + + string typeStr = VFXExpression.TypeToCode(type); + codeBuilder.Append($"{typeStr} {variableName} = {value};\n"); + } + + void AddInputVariableValueString(VFXExpression uniform, string entry) + { + m_InputVariableValueStrings[uniform] = entry; + } + + void AddGeneratedVariableValueString(VFXExpression expression, string entry) + { + m_GeneratedVariableValueStrings[expression] = entry; + } + + bool HasVariableValueString(VFXExpression expression) + { + return m_GeneratedVariableValueStrings.ContainsKey(expression) || + m_InputVariableValueStrings.ContainsKey(expression); + } + + } +} diff --git a/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs.meta new file mode 100644 index 00000000000..ffaf2ccf55a --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/NewCompiler/VfxSubTaskBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5ca1ba9147f74462af8be76c38d3d7b2 +timeCreated: 1772636994 \ No newline at end of file diff --git a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Data/ByteAddressBuffer.hlsl b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Data/ByteAddressBuffer.hlsl index 675959e862a..9769020a14f 100644 --- a/Packages/com.unity.visualeffectgraph/Shaders/Temp/Data/ByteAddressBuffer.hlsl +++ b/Packages/com.unity.visualeffectgraph/Shaders/Temp/Data/ByteAddressBuffer.hlsl @@ -225,20 +225,27 @@ struct VFXByteAddressBuffer data = 0u; if (valid && readAccess) { + float4 c0, c1, c2, c3; if (writeAccess) { - data[0] = asfloat(bufferRW.Load4((offset + index + 0) << 2)); - data[1] = asfloat(bufferRW.Load4((offset + index + 4) << 2)); - data[2] = asfloat(bufferRW.Load4((offset + index + 8) << 2)); - data[3] = asfloat(bufferRW.Load4((offset + index + 12) << 2)); + c0 = asfloat(bufferRW.Load4((offset + index + 0) << 2)); + c1 = asfloat(bufferRW.Load4((offset + index + 4) << 2)); + c2 = asfloat(bufferRW.Load4((offset + index + 8) << 2)); + c3 = asfloat(bufferRW.Load4((offset + index + 12) << 2)); } else { - data[0] = asfloat(buffer.Load4((offset + index + 0) << 2)); - data[1] = asfloat(buffer.Load4((offset + index + 4) << 2)); - data[2] = asfloat(buffer.Load4((offset + index + 8) << 2)); - data[3] = asfloat(buffer.Load4((offset + index + 12) << 2)); + c0 = asfloat(buffer.Load4((offset + index + 0) << 2)); + c1 = asfloat(buffer.Load4((offset + index + 4) << 2)); + c2 = asfloat(buffer.Load4((offset + index + 8) << 2)); + c3 = asfloat(buffer.Load4((offset + index + 12) << 2)); } + data = float4x4( + c0.x, c1.x, c2.x, c3.x, + c0.y, c1.y, c2.y, c3.y, + c0.z, c1.z, c2.z, c3.z, + c0.w, c1.w, c2.w, c3.w + ); } return valid; } @@ -248,10 +255,10 @@ struct VFXByteAddressBuffer bool valid = !rangeCheck || index + 15 < size; if (valid && writeAccess) { - for (int i = 0; i < 4; ++i) - { - bufferRW.Store4((offset + index + 4 * i) << 2, data[i]); - } + bufferRW.Store4((offset + index + 0) << 2, asuint(float4(data[0].x, data[1].x, data[2].x, data[3].x))); + bufferRW.Store4((offset + index + 4) << 2, asuint(float4(data[0].y, data[1].y, data[2].y, data[3].y))); + bufferRW.Store4((offset + index + 8) << 2, asuint(float4(data[0].z, data[1].z, data[2].z, data[3].z))); + bufferRW.Store4((offset + index + 12) << 2, asuint(float4(data[0].w, data[1].w, data[2].w, data[3].w))); } return valid; } From 2a6e6e60aaa2cd304855ceab0d41037d96849987 Mon Sep 17 00:00:00 2001 From: Volkan Ilbeyli Date: Tue, 21 Apr 2026 10:21:10 +0000 Subject: [PATCH 24/56] [UpscalerFramework] fix warnings in HDRP and URP --- .../RenderPipeline/HDRenderPipeline.PostProcess.cs | 2 +- .../Runtime/Debug/DebugDisplaySettingsRendering.cs | 10 +++++++++- .../Passes/PostProcess/UpscalerPostProcessPass.cs | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index 2e7b6e52bb5..145ed426cd9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs @@ -1074,7 +1074,7 @@ TextureHandle inputStencil io.previousPreUpscaleResolution = hdCamera.historyRTHandleProperties.previousViewportSize; io.postUpscaleResolution = new Vector2Int((int)hdCamera.finalViewport.width, (int)hdCamera.finalViewport.height); io.enableTexArray = TextureXR.useTexArray; - io.cameraInstanceID = hdCamera.camera.GetEntityId().GetRawData(); + io.cameraInstanceID = EntityId.ToULong(hdCamera.camera.GetEntityId()); io.nearClipPlane = hdCamera.camera.nearClipPlane; io.farClipPlane = hdCamera.camera.farClipPlane; io.fieldOfViewDegrees = hdCamera.camera.fieldOfView; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsRendering.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsRendering.cs index 4fbafd82804..60ad8a2ebdd 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsRendering.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsRendering.cs @@ -214,7 +214,15 @@ internal bool blockReflectionProbeAtlasOverlay /// but the Universal Render Pipeline's upscaling filter is not set to STP. /// internal bool blockSTPOverlay { - get { return fullScreenDebugMode == DebugFullScreenMode.STP && UniversalRenderPipeline.asset.upscalingFilter != UpscalingFilterSelection.STP; } + get { + var asset = UniversalRenderPipeline.asset; + return asset != null && fullScreenDebugMode == DebugFullScreenMode.STP && +#if ENABLE_UPSCALER_FRAMEWORK + asset.upscalerName != STPIUpscaler.upscalerName; +#else + asset.upscalingFilter != UpscalingFilterSelection.STP; +#endif + } } #region Pixel validation diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs index b77c5e707e8..22ef5d258b8 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs @@ -70,7 +70,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer Debug.Assert(motionData != null); } - io.cameraInstanceID = cameraData.camera.GetEntityId().GetRawData(); + io.cameraInstanceID = EntityId.ToULong(cameraData.camera.GetEntityId()); io.nearClipPlane = cameraData.camera.nearClipPlane; io.farClipPlane = cameraData.camera.farClipPlane; io.fieldOfViewDegrees = cameraData.camera.fieldOfView; From 346b310fa861a7e55f944ed8b06d642470f2dd3b Mon Sep 17 00:00:00 2001 From: Angela Dematte Date: Tue, 21 Apr 2026 10:21:13 +0000 Subject: [PATCH 25/56] Disable unstable VFX test on WindowsEditor platform --- .../Assets/AllTests/Editor/Tests/VFXViewWindowTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXViewWindowTests.cs b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXViewWindowTests.cs index 4faea09e7f4..a50c13afd2d 100644 --- a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXViewWindowTests.cs +++ b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXViewWindowTests.cs @@ -41,6 +41,7 @@ public void TearDown() } [UnityTest] + [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WindowsEditor })] // Unstable: https://jira.unity3d.com/browse/UUM-140366 public IEnumerator Create_New_ShaderGraph_Output_Context() { const int kTemplateWindowTimeoutInMs = 5000; From e0d36521fcccb1ac1306e35f07520f0e5e96bfa8 Mon Sep 17 00:00:00 2001 From: Roland Kindermann Date: Tue, 21 Apr 2026 20:39:13 +0000 Subject: [PATCH 26/56] Fix Rendering Debugger Reset not clearing pinned persistent UI elements (UUM-139701) --- .../Runtime/Debugging/DebugManager.UIState.cs | 2 +- .../Runtime/Debugging/DebugManager.cs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs index f0d30531a58..e8b3b20fcca 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs @@ -152,7 +152,7 @@ public bool displayPersistentRuntimeUI } else { - CoreUtils.Destroy(m_RuntimePersistentDebugUI.gameObject); + CoreUtils.Destroy(m_RuntimePersistentDebugUI?.gameObject); m_RuntimePersistentDebugUI = null; } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.cs index da39f05dd35..26d5fe684f3 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.cs @@ -193,6 +193,10 @@ public void Reset() DebugDisplaySerializer.SaveFoldoutStates(); DebugDisplaySerializer.Clear(); resetData?.Invoke(); +#if ENABLE_RENDERING_DEBUGGER_UI + displayPersistentRuntimeUI = false; + ForEachWidget(w => { if (w is DebugUI.ValueTuple vt) vt.pinnedElementIndex = -1; }); +#endif } /// From 2c8d9aa703fd280c280d7b7d10489573830e3b4c Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Tue, 21 Apr 2026 20:39:16 +0000 Subject: [PATCH 27/56] Fix Rendering Debugger enum dropdowns going blank after Reset (UUM-138138) --- .../Runtime/Debugging/DebugUI.Fields.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 385e6af9984..428dd8b15ec 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 @@ -875,8 +875,11 @@ protected override VisualElement Create() this.ScheduleTracked(field, () => field.schedule.Execute(() => { - if (currentIndex >= 0 && currentIndex < enumNames.Length) - field.SetValueWithoutNotify(enumNames[currentIndex].text); + // https://jira.unity3d.com/browse/UUM-138138: Clamp currentIndex to 0. This matches old IMGUI + // DebugUIDrawer behavior where a negative index is sometimes used to denote an invalid/none value. + int index = Mathf.Max(0, currentIndex); + if (index < enumNames.Length) + field.SetValueWithoutNotify(enumNames[index].text); }).Every(100)); m_AdditionalSearchText = string.Join(",", field.choices); From f7d89855a8f77c9d7c69324c45d0fda9e7900d33 Mon Sep 17 00:00:00 2001 From: Jeannette Yu Date: Wed, 22 Apr 2026 11:19:39 +0000 Subject: [PATCH 28/56] [XR] Fix missing unity_StereoEyeIndex constant in URP Multi-pass, needed for stereoscopic panoramic skyboxes --- .../Runtime/XR/XRBuiltinShaderConstants.cs | 5 +++++ .../Runtime/ScriptableRenderer.cs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRBuiltinShaderConstants.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRBuiltinShaderConstants.cs index cbbd2cee2dc..df9f0be4d19 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRBuiltinShaderConstants.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRBuiltinShaderConstants.cs @@ -52,6 +52,11 @@ public static class XRBuiltinShaderConstants /// static public readonly int unity_StereoWorldSpaceCameraPos = Shader.PropertyToID("unity_StereoWorldSpaceCameraPos"); + /// + /// Cached unique id for unity_StereoEyeIndex + /// + static public readonly int unity_StereoEyeIndex = Shader.PropertyToID("unity_StereoEyeIndex"); + // Pre-allocate arrays to avoid GC static Matrix4x4[] s_cameraProjMatrix = new Matrix4x4[2]; static Matrix4x4[] s_invCameraProjMatrix = new Matrix4x4[2]; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs index 659365b7242..132218f3d0b 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs @@ -235,6 +235,10 @@ void SetPerCameraShaderVariables(RasterCommandBuffer cmd, UniversalCameraData ca { cameraWidth = (float)cameraTargetSizeCopy.x; cameraHeight = (float)cameraTargetSizeCopy.y; + + // Multi-pass needs to set unity_StereoEyeIndex builtin param for skybox-panoramic.shader to work correctly (UUM-120719) + if (!cameraData.xr.singlePassEnabled) + cmd.SetGlobalVector(XRBuiltinShaderConstants.unity_StereoEyeIndex, new Vector4(cameraData.xr.multipassId, 0, 0, 0)); } if (camera.allowDynamicResolution) From eb10b2002eaa803c9dfa93228adc60728069d7f1 Mon Sep 17 00:00:00 2001 From: Roland Kindermann Date: Wed, 22 Apr 2026 11:19:41 +0000 Subject: [PATCH 29/56] Fix "Search string limit exceeded" warning in Rendering Debugger search field --- .../Editor/Utilities/UIElementSearchFilter.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs b/Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs index 9e9e21d03a8..65e95f98cda 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs @@ -11,7 +11,7 @@ class UIElementSearchFilter { internal const string k_SelectionColorBeginTag = ""; internal const string k_SelectionColorEndTag = ""; - const int k_SearchStringLimit = 15; + const int k_SearchStringLimit = 32; IVisualElementScheduledItem m_PreviousSearch; string m_PendingSearchString; @@ -28,6 +28,7 @@ public void InitializeSearchField(string searchFieldName) { var searchField = m_RootElement.Q(searchFieldName); searchField.placeholderText = L10n.Tr("Search"); + searchField.Q().maxLength = k_SearchStringLimit; searchField.RegisterValueChangedCallback(evt => OnSearchFilterChanged(evt.newValue)); // Apply empty search once in case the entire window was reloaded with a non-empty search. Search @@ -37,13 +38,6 @@ public void InitializeSearchField(string searchFieldName) void OnSearchFilterChanged(string searchString) { - // Ensure the search string is within the allowed length limit - if (searchString.Length > k_SearchStringLimit) - { - searchString = searchString[..k_SearchStringLimit]; - Debug.LogWarning($"Search string limit exceeded: {k_SearchStringLimit}"); - } - // Sanitize to not match rich text tags searchString = searchString.Replace("<", string.Empty).Replace(">", string.Empty); From f5ee508b11eaa0508d7741e32345cd8d87b75052 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Wed, 22 Apr 2026 16:01:10 +0000 Subject: [PATCH 30/56] Reset static variables for CoreCLR / Fast Enter Play Mode (SRP Core Team, render-pipelines.high-definition package) --- .../Runtime/Core/CoreResources/GPUCopy.cs | 2 +- .../Debugging/FrameSettingsFieldAttribute.cs | 12 +- .../Runtime/Core/Textures/EncodeBC6H.cs | 123 ------------------ .../Runtime/Core/Textures/EncodeBC6H.cs.meta | 11 -- .../Runtime/Core/Textures/TextureCache.cs | 10 +- .../Runtime/Debug/DebugDisplay.cs | 28 ++-- .../CustomPostProcessVolumeComponent.cs | 4 +- .../Runtime/RenderPipeline/Camera/HDCamera.cs | 10 +- .../RenderPipeline/CullingGroupManager.cs | 18 +-- .../RenderPipeline/HDDynamicResolution.cs | 8 ++ ...HDDynamicResolutionPlatformCapabilities.cs | 6 +- .../RenderPipeline/HDRenderPipeline.Debug.cs | 6 +- .../HDRenderPipeline.Prepass.cs | 10 +- .../RenderPipeline/HDRenderPipeline.cs | 27 ++-- .../RenderPipeline/HDRenderPipelineAsset.cs | 3 - ...DRenderPipelineGlobalSettings.Migration.cs | 3 +- .../Raytracing/HDRaytracingManager.cs | 67 ++++++---- .../RenderPass/CustomPass/CustomPassUtils.cs | 85 +++++++----- .../RenderPass/CustomPass/CustomPassVolume.cs | 17 ++- .../RenderPass/DrawRenderersCustomPass.cs | 15 +-- .../Settings/CaptureSettings.cs | 3 +- .../RenderPipeline/Settings/FrameSettings.cs | 2 +- .../Settings/FrameSettingsDefaults.cs | 6 +- .../Settings/FrameSettingsHistory.cs | 45 ++++--- .../Runtime/RenderPipeline/Utility/HDUtils.cs | 20 +-- 25 files changed, 241 insertions(+), 300 deletions(-) delete mode 100644 Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs delete mode 100644 Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs.meta diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUCopy.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUCopy.cs index e83a1e45069..f7c4f617e2f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUCopy.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUCopy.cs @@ -16,7 +16,7 @@ public GPUCopy(ComputeShader shader) static readonly int _RectOffset = Shader.PropertyToID("_RectOffset"); static readonly int _Result1 = Shader.PropertyToID("_Result1"); static readonly int _Source4 = Shader.PropertyToID("_Source4"); - static int[] _IntParams = new int[2]; + static readonly int[] _IntParams = new int[2]; void SampleCopyChannel( CommandBuffer cmd, diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Debugging/FrameSettingsFieldAttribute.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Debugging/FrameSettingsFieldAttribute.cs index 182cf3f87c2..ce9dfab70a6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Debugging/FrameSettingsFieldAttribute.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Debugging/FrameSettingsFieldAttribute.cs @@ -2,6 +2,7 @@ using System.Text; using System.Collections.Generic; using System.Reflection; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.HighDefinition { @@ -42,9 +43,10 @@ public enum DisplayType { BoolAsCheckbox, BoolAsEnumPopup, Others } public readonly FrameSettingsField[] dependencies; private readonly int dependencySeparator; - static int autoOrder = 0; - - private static Dictionary s_FrameSettingsEnumNameMap = null; + // No cleanup needed (only modified when FrameSettingsFieldAttribute are instantiated) + [NoAutoStaticsCleanup] static int s_AutoOrder = 0; + // No cleanup needed (reflection data cache) + [NoAutoStaticsCleanup] static Dictionary s_FrameSettingsEnumNameMap = null; public static Dictionary GetEnumNameMap() { @@ -103,8 +105,8 @@ public FrameSettingsFieldAttribute( // Editor and Runtime debug menu this.group = group; if (customOrderInGroup != -1) - autoOrder = customOrderInGroup; //start again numbering from this value - this.orderInGroup = autoOrder++; + s_AutoOrder = customOrderInGroup; //start again numbering from this value + this.orderInGroup = s_AutoOrder++; this.displayedName = displayedName; this.type = type; this.targetType = targetType; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs deleted file mode 100644 index 6a59634b969..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs +++ /dev/null @@ -1,123 +0,0 @@ -using UnityEngine.Assertions; -using UnityEngine.Experimental.Rendering; - -namespace UnityEngine.Rendering -{ - class EncodeBC6H - { - public static EncodeBC6H DefaultInstance; - - static readonly int _Source = Shader.PropertyToID("_Source"); - static readonly int _Target = Shader.PropertyToID("_Target"); - static readonly int _MipIndex = Shader.PropertyToID("_MipIndex"); - static readonly int[] __Tmp_RT = - { - Shader.PropertyToID("__Tmp_RT0"), - Shader.PropertyToID("__Tmp_RT1"), - Shader.PropertyToID("__Tmp_RT2"), - Shader.PropertyToID("__Tmp_RT3"), - Shader.PropertyToID("__Tmp_RT4"), - Shader.PropertyToID("__Tmp_RT5"), - Shader.PropertyToID("__Tmp_RT6"), - Shader.PropertyToID("__Tmp_RT7"), - Shader.PropertyToID("__Tmp_RT8"), - Shader.PropertyToID("__Tmp_RT9"), - Shader.PropertyToID("__Tmp_RT10"), - Shader.PropertyToID("__Tmp_RT11"), - Shader.PropertyToID("__Tmp_RT12"), - Shader.PropertyToID("__Tmp_RT13") - }; - - readonly ComputeShader m_Shader; - readonly int m_KEncodeFastCubemapMip; - - public EncodeBC6H(ComputeShader shader) - { - Assert.IsNotNull(shader); - - m_Shader = shader; - m_KEncodeFastCubemapMip = m_Shader.FindKernel("KEncodeFastCubemapMip"); - - // Disabling this code as we currently don't use BC6H encoding and it seems to create issue when enabling virtual texturing. - //uint x, y, z; - //m_Shader.GetKernelThreadGroupSizes(m_KEncodeFastCubemapMip, out x, out y, out z); - } - - // Only use mode11 of BC6H encoding - /// - /// Encode a Cubemap in BC6H. - /// - /// It will encode all faces and selected mips of the Cubemap. - /// - /// It uses only mode 11 of BC6H. - /// - /// Command buffer for execution - /// The source Cubemap - /// The size of the source Cubemap - /// The compressed texture. - /// It must be a BC6H Cubemap or Cubemap array with the same size as the source Cubemap - /// Starting mip to encode - /// Last mip to encode - /// The index of the cubemap to store the compressed texture. - /// - /// Only relevant when target is a CubemapArray - public void EncodeFastCubemap(CommandBuffer cmb, RenderTargetIdentifier source, int sourceSize, RenderTargetIdentifier target, int fromMip, int toMip, int targetArrayIndex = 0) - { - var maxMip = Mathf.Max(0, (int)(Mathf.Log(sourceSize) / Mathf.Log(2)) - 2); - var actualFromMip = (int)Mathf.Clamp(fromMip, 0, maxMip); - var actualToMip = (int)Mathf.Min(maxMip, Mathf.Max(toMip, actualFromMip)); - - // Convert TextureCube source to Texture2DArray - var d = new RenderTextureDescriptor - { - autoGenerateMips = false, - bindMS = false, - graphicsFormat = GraphicsFormat.R32G32B32A32_SInt, - depthBufferBits = 0, - dimension = TextureDimension.Tex2DArray, - enableRandomWrite = true, - msaaSamples = 1, - volumeDepth = 6, - sRGB = false, - useMipMap = false, - }; - - cmb.SetComputeTextureParam(m_Shader, m_KEncodeFastCubemapMip, _Source, source); - - for (var mip = actualFromMip; mip <= actualToMip; ++mip) - { - var size = (sourceSize >> mip) >> 2; - d.width = size; - d.height = size; - cmb.GetTemporaryRT(__Tmp_RT[mip], d); - } - - for (var mip = actualFromMip; mip <= actualToMip; ++mip) - { - var size = (sourceSize >> mip) >> 2; - cmb.SetComputeTextureParam(m_Shader, m_KEncodeFastCubemapMip, _Target, __Tmp_RT[mip]); - cmb.SetComputeIntParam(m_Shader, _MipIndex, mip); - cmb.DispatchCompute(m_Shader, m_KEncodeFastCubemapMip, size, size, 6); - } - - var startSlice = 6 * targetArrayIndex; - for (var mip = actualFromMip; mip <= actualToMip; ++mip) - { - var rtMip = Mathf.Clamp(mip, actualFromMip, actualToMip); - for (var faceId = 0; faceId < 6; ++faceId) - cmb.CopyTexture(__Tmp_RT[rtMip], faceId, 0, target, startSlice + faceId, mip); - } - - for (var mip = actualFromMip; mip <= actualToMip; ++mip) - cmb.ReleaseTemporaryRT(__Tmp_RT[mip]); - } - } - - internal static class BC6HExtensions - { - public static void BC6HEncodeFastCubemap(this CommandBuffer cmb, RenderTargetIdentifier source, int sourceSize, RenderTargetIdentifier target, int fromMip, int toMip, int targetArrayIndex = 0) - { - EncodeBC6H.DefaultInstance.EncodeFastCubemap(cmb, source, sourceSize, target, fromMip, toMip, targetArrayIndex); - } - } -} diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs.meta deleted file mode 100644 index b601df417a7..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/EncodeBC6H.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 379274e2dbcfbc247acccd1aab4243ee -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/TextureCache.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/TextureCache.cs index 628aea3cdd9..2501d6f24b9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/TextureCache.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/TextureCache.cs @@ -39,7 +39,7 @@ private struct SliceEntry private Texture[] m_autoContentArray = new Texture[1]; // Constant values - private static uint g_MaxFrameCount = unchecked((uint)(-1)); + const uint k_MaxFrameCount = unchecked((uint)(-1)); protected const int k_FP16SizeInByte = 2; protected const int k_NbChannel = 4; @@ -81,7 +81,7 @@ protected bool AllocTextureArray(int numTextures) m_NumTextures = numTextures / m_SliceSize; for (int i = 0; i < m_NumTextures; i++) { - m_SliceArray[i].countLRU = g_MaxFrameCount; // never used before + m_SliceArray[i].countLRU = k_MaxFrameCount; // never used before m_SliceArray[i].texId = EntityId.None; m_SortedIdxArray[i] = i; } @@ -208,7 +208,7 @@ public int FetchSlice(CommandBuffer cmd, Texture texture, uint textureHash, bool return sliceIndex; } - private static List s_TempIntList = new List(); + private static readonly List s_TempIntList = new List(); // No clear needed for static member, always cleared before usage public void NewFrame() { var numNonZeros = 0; @@ -235,7 +235,7 @@ public void NewFrame() for (int i = 0; i < m_NumTextures; i++) { - if (m_SliceArray[i].countLRU < g_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame + if (m_SliceArray[i].countLRU < k_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame } //for(int q=1; q instances = new HashSet(); + [NoAutoStaticsCleanup] // Cleaned up when pipeline is disposed by calling CleanupAllCustomPostProcesses() + internal static readonly HashSet instances = new HashSet(); /// /// Injection point of the custom post process in HDRP. 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 558dc822239..13774a78bec 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 @@ -5,6 +5,7 @@ using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using Unity.Collections; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.HighDefinition { @@ -1945,8 +1946,8 @@ internal bool isSceneViewCameraWithExposureOverride && m_AdditionalCameraData.doesSceneViewOverrideExposure; internal float sceneViewExposureOverride - => m_AdditionalCameraData == null - ? 10f + => m_AdditionalCameraData == null + ? 10f : m_AdditionalCameraData.sceneViewOverrideExposureValue; #endif @@ -1955,9 +1956,10 @@ internal float sceneViewExposureOverride #region Private API + // s_Cameras and s_Cleanup are cleared when pipeline is disposed by calling HDCamera.ClearAll() + [NoAutoStaticsCleanup] static readonly Dictionary<(Camera, int, HistoryChannel), HDCamera> s_Cameras = new Dictionary<(Camera, int, HistoryChannel), HDCamera>(); + [NoAutoStaticsCleanup] static readonly List<(Camera, int, HistoryChannel)> s_Cleanup = new List<(Camera, int, HistoryChannel)>(); // Recycled to reduce GC pressure - static Dictionary<(Camera, int, HistoryChannel), HDCamera> s_Cameras = new Dictionary<(Camera, int, HistoryChannel), HDCamera>(); - static List<(Camera, int, HistoryChannel)> s_Cleanup = new List<(Camera, int, HistoryChannel)>(); // Recycled to reduce GC pressure HDAdditionalCameraData m_AdditionalCameraData = null; // Init in Update BufferedRTHandleSystem m_HistoryRTSystem = new BufferedRTHandleSystem(); int m_HistoryViewCount = 0; // Used to track view count change if XR is enabled/disabled diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/CullingGroupManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/CullingGroupManager.cs index c21f9e2d73b..b1d5d05a2ea 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/CullingGroupManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/CullingGroupManager.cs @@ -4,16 +4,18 @@ namespace UnityEngine.Rendering.HighDefinition { class CullingGroupManager { - static CullingGroupManager m_Instance; - static public CullingGroupManager instance + static CullingGroupManager s_Instance; + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() { - get - { - if (m_Instance == null) - m_Instance = new CullingGroupManager(); - return m_Instance; - } + s_Instance?.Cleanup(); + s_Instance = null; } +#endif + + public static CullingGroupManager instance => s_Instance ??= new CullingGroupManager(); private Stack m_FreeList = new Stack(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolution.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolution.cs index 7a578486223..bef3af8658f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolution.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolution.cs @@ -13,6 +13,14 @@ /// public class HDDynamicResolution : MonoBehaviour { +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + ResetScale(); + } +#endif + /// /// Target frame rate for dynamic resolution. If Application.targetFrameRate is already set, Application.targetFrameRate overrides this parameter. /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolutionPlatformCapabilities.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolutionPlatformCapabilities.cs index 2ff4537bdf3..b4c57fae192 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolutionPlatformCapabilities.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDDynamicResolutionPlatformCapabilities.cs @@ -1,3 +1,4 @@ +using Unity.Scripting.LifecycleManagement; using UnityEngine; namespace UnityEngine.Rendering.HighDefinition @@ -17,8 +18,9 @@ public static class HDDynamicResolutionPlatformCapabilities /// public static bool FSR2Detected { get { return m_FSR2Detected; } } - private static bool m_DLSSDetected = false; - private static bool m_FSR2Detected = false; + // No cleanup needed, initialized during pipeline construction + [NoAutoStaticsCleanup] static bool m_DLSSDetected = false; + [NoAutoStaticsCleanup] static bool m_FSR2Detected = false; internal static void SetupFeatures() { 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 98b3eb6ec38..d1b54f783e7 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 @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Unity.Scripting.LifecycleManagement; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; @@ -49,12 +50,13 @@ public partial class HDRenderPipeline /// Debug display settings. /// public DebugDisplaySettings debugDisplaySettings => m_DebugDisplaySettings; - private static DebugDisplaySettings s_NeutralDebugDisplaySettings; + [NoAutoStaticsCleanup] // No cleanup needed, always initialized at pipeline create + static DebugDisplaySettings s_NeutralDebugDisplaySettings; internal DebugDisplaySettings m_CurrentDebugDisplaySettings; void InitializeDebug() { - s_NeutralDebugDisplaySettings ??= new DebugDisplaySettings(); + 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.Prepass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs index ec351667d45..8729593c7d1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs @@ -1316,12 +1316,12 @@ internal struct DBufferOutput public int dBufferCount; } - static string[] s_DBufferNames = { "DBuffer0", "DBuffer1", "DBuffer2", "DBuffer3" }; + static readonly string[] s_DBufferNames = { "DBuffer0", "DBuffer1", "DBuffer2", "DBuffer3" }; - static Color s_DBufferClearColor = new Color(0.0f, 0.0f, 0.0f, 1.0f); - static Color s_DBufferClearColorNormal = new Color(0.5f, 0.5f, 0.5f, 1.0f); // for normals 0.5 is neutral - static Color s_DBufferClearColorAOSBlend = new Color(1.0f, 1.0f, 1.0f, 1.0f); - static Color[] s_DBufferClearColors = { s_DBufferClearColor, s_DBufferClearColorNormal, s_DBufferClearColor, s_DBufferClearColorAOSBlend }; + static readonly Color s_DBufferClearColor = new Color(0.0f, 0.0f, 0.0f, 1.0f); + static readonly Color s_DBufferClearColorNormal = new Color(0.5f, 0.5f, 0.5f, 1.0f); // for normals 0.5 is neutral + static readonly Color s_DBufferClearColorAOSBlend = new Color(1.0f, 1.0f, 1.0f, 1.0f); + static readonly Color[] s_DBufferClearColors = { s_DBufferClearColor, s_DBufferClearColorNormal, s_DBufferClearColor, s_DBufferClearColorAOSBlend }; void SetupDBufferTargets(RenderGraph renderGraph, bool use4RTs, ref PrepassOutput output, IUnsafeRenderGraphBuilder builder, bool canReadBoundDepthBuffer) { 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 c69ee655b9e..944db9dfcda 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 @@ -3,6 +3,7 @@ using System; using System.Diagnostics; using System.Linq; +using Unity.Scripting.LifecycleManagement; using UnityEngine.Experimental.GlobalIllumination; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; @@ -95,9 +96,9 @@ internal static HDRenderPipeline currentPipeline bool m_FrameSettingsHistoryEnabled = false; #if UNITY_SWITCH - internal static bool k_PreferFragment = true; + internal static readonly bool k_PreferFragment = true; #else - internal static bool k_PreferFragment = false; + internal static readonly bool k_PreferFragment = false; #endif /// @@ -441,10 +442,12 @@ void SetHDRState(HDCamera camera) // MSAA resolve materials Material m_ColorResolveMaterial = null; Material m_MotionVectorResolve = null; - static int s_ColorResolve1XPassIndex; - static int s_ColorResolve2XPassIndex; - static int s_ColorResolve4XPassIndex; - static int s_ColorResolve8XPassIndex; + + // No reset needed, always initialized at pipeline create + [NoAutoStaticsCleanup] static int s_ColorResolve1XPassIndex; + [NoAutoStaticsCleanup] static int s_ColorResolve2XPassIndex; + [NoAutoStaticsCleanup] static int s_ColorResolve4XPassIndex; + [NoAutoStaticsCleanup] static int s_ColorResolve8XPassIndex; WorldLights m_WorldLights = new WorldLights(); WorldLightsGpu m_WorldLightsGpu = new WorldLightsGpu(); @@ -602,8 +605,6 @@ public HDRenderPipeline(HDRenderPipelineAsset asset) m_MipGenerator = new MipGenerator(this); m_BlueNoise = new BlueNoise(this); - EncodeBC6H.DefaultInstance = EncodeBC6H.DefaultInstance ?? new EncodeBC6H(runtimeShaders.encodeBC6HCS); - // Scan material list and assign it m_MaterialList = HDUtils.GetRenderPipelineMaterialList(); @@ -1344,7 +1345,7 @@ void ConfigureKeywords(bool enableBakeShadowMask, HDCamera hdCamera, CommandBuff // only the remapping shader functions. EnableFoveatedRemapping() can be used also with // rasterization passes where foveated rasterization isn't desired (e.g. full-screen pass with // foveated remapping in shaders). - static GlobalKeyword _FOVEATED_RENDERING_NON_UNIFORM_RASTER = GlobalKeyword.Create("_FOVEATED_RENDERING_NON_UNIFORM_RASTER"); + static readonly GlobalKeyword _FOVEATED_RENDERING_NON_UNIFORM_RASTER = GlobalKeyword.Create("_FOVEATED_RENDERING_NON_UNIFORM_RASTER"); /// /// Enable foveated rasterization state and foveated coordinate remapping by FoveatedRemap*() shader functions. @@ -2033,7 +2034,9 @@ ScriptableRenderContext renderContext visibleProbe.RepeatRenderSteps(skippedRenderSteps); } - static List<(int index, float weight)> s_TempGenerateProbeRenderRequestsList = new List<(int index, float weight)>(); + + [NoAutoStaticsCleanup] // No clear needed, always cleared before use + static readonly List<(int index, float weight)> s_TempGenerateProbeRenderRequestsList = new List<(int index, float weight)>(); void GenerateProbeRenderRequests( Dictionary> renderRequestIndicesWhereTheProbeIsVisible, @@ -2541,8 +2544,8 @@ protected override bool IsRenderRequestSupported(Camera camera, Req return false; } - // To prevent run-time alloc - static List s_RenderRequestCamera = new List(); + [NoAutoStaticsCleanup] // No need to clear, always cleared before use + static readonly List s_RenderRequestCamera = new List(); // To prevent run-time alloc static readonly AOVRequestDataCollection s_EmptyAOVRequests = new AOVRequestDataCollection(null); /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs index 2fa47414308..2a1216d1dab 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -172,9 +172,6 @@ public VolumeProfile volumeProfile set => m_VolumeProfile = value; } - static string[] s_Names; - static int[] s_Values; - /// Names used for display of rendering layer masks. [Obsolete("This property is obsolete. Use RenderingLayerMask API and Tags & Layers project settings instead. #from(2023.3)")] public override string[] renderingLayerMaskNames => UnityEngine.RenderingLayerMask.GetDefinedRenderingLayerNames(); 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 34e2820032e..12f3726acf0 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 @@ -1,6 +1,7 @@ using System; using System.Linq; using Unity.RenderPipelines.Core.Runtime.Shared; +using Unity.Scripting.LifecycleManagement; #if UNITY_EDITOR using UnityEditor.Rendering; @@ -39,7 +40,7 @@ internal enum Version RenderingLayerMask, } - static Version[] skipedStepWhenCreatedFromHDRPAsset = new Version[] { }; + [NoAutoStaticsCleanup] static readonly Version[] skipedStepWhenCreatedFromHDRPAsset = new Version[] { }; [SerializeField] internal Version m_Version = MigrationDescription.LastVersion(); 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 74e56607fb3..f54d5b5452d 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 @@ -66,11 +66,22 @@ public partial class HDRenderPipeline RayCountManager m_RayCountManager; // Static variables used for the dirtiness and manual rtas management - const int maxNumSubMeshes = 32; - static RayTracingSubMeshFlags[] subMeshFlagArray = new RayTracingSubMeshFlags[maxNumSubMeshes]; - static uint[] vfxSystemMasks = new uint[maxNumSubMeshes]; - static List materialArray = new List(maxNumSubMeshes); - static Dictionary m_MaterialCRCs = new Dictionary(); + const int k_MaxNumSubMeshes = 32; + static readonly RayTracingSubMeshFlags[] s_SubMeshFlagArray = new RayTracingSubMeshFlags[k_MaxNumSubMeshes]; + static readonly uint[] s_VfxSystemMasks = new uint[k_MaxNumSubMeshes]; + static readonly List s_MaterialArray = new List(k_MaxNumSubMeshes); + static readonly Dictionary s_MaterialCRCs = new Dictionary(); + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad_HDRaytracingManager() + { + System.Array.Clear(s_SubMeshFlagArray, 0, s_SubMeshFlagArray.Length); + System.Array.Clear(s_VfxSystemMasks, 0, s_VfxSystemMasks.Length); + s_MaterialArray?.Clear(); + s_MaterialCRCs?.Clear(); + } +#endif // Global shader variables ray tracing lightloop constant buffer ShaderVariablesRaytracingLightLoop m_ShaderVariablesRaytracingLightLoopCB = new ShaderVariablesRaytracingLightLoop(); @@ -207,14 +218,14 @@ static bool IsAlphaTestedMaterial(Material currentMaterial) private static bool UpdateMaterialCRC(EntityId matInstanceId, int matCRC) { int matPrevCRC; - if (m_MaterialCRCs.TryGetValue(matInstanceId, out matPrevCRC)) + if (s_MaterialCRCs.TryGetValue(matInstanceId, out matPrevCRC)) { - m_MaterialCRCs[matInstanceId] = matCRC; + s_MaterialCRCs[matInstanceId] = matCRC; return (matCRC != matPrevCRC); } else { - m_MaterialCRCs.Add(matInstanceId, matCRC); + s_MaterialCRCs.Add(matInstanceId, matCRC); return true; } } @@ -244,22 +255,22 @@ private static AccelerationStructureStatus AddRegularInstanceToRAS(RayTracingAcc { SkinnedMeshRenderer skinnedMesh = (SkinnedMeshRenderer)currentRenderer; if (skinnedMesh.sharedMesh == null) return AccelerationStructureStatus.MissingMesh; - currentRenderer.GetSharedMaterials(materialArray); + currentRenderer.GetSharedMaterials(s_MaterialArray); numSubMeshes = skinnedMesh.sharedMesh.subMeshCount; } else { currentRenderer.TryGetComponent(out MeshFilter meshFilter); if (meshFilter == null || meshFilter.sharedMesh == null) return AccelerationStructureStatus.MissingMesh; - currentRenderer.GetSharedMaterials(materialArray); + currentRenderer.GetSharedMaterials(s_MaterialArray); numSubMeshes = meshFilter.sharedMesh.subMeshCount; } // If the material array is null, we are done - if (materialArray == null) return AccelerationStructureStatus.NullMaterial; + if (s_MaterialArray == null) return AccelerationStructureStatus.NullMaterial; // Let's clamp the number of sub-meshes to avoid throwing an unwanted error - numSubMeshes = Mathf.Min(numSubMeshes, maxNumSubMeshes); + numSubMeshes = Mathf.Min(numSubMeshes, k_MaxNumSubMeshes); bool doubleSided = false; bool materialIsOnlyTransparent = true; @@ -268,10 +279,10 @@ private static AccelerationStructureStatus AddRegularInstanceToRAS(RayTracingAcc { // Initially we consider the potential mesh as invalid bool validMesh = false; - if (materialArray.Count > subGeomIdx) + if (s_MaterialArray.Count > subGeomIdx) { // Grab the material for the current sub-mesh - Material currentMaterial = materialArray[subGeomIdx]; + Material currentMaterial = s_MaterialArray[subGeomIdx]; // Make sure that the material is HDRP's and non-decal if (IsValidRayTracedMaterial(currentMaterial)) @@ -299,13 +310,13 @@ private static AccelerationStructureStatus AddRegularInstanceToRAS(RayTracingAcc // If the mesh was not valid, exclude it (without affecting sidedness) if (!validMesh) - subMeshFlagArray[subGeomIdx] = RayTracingSubMeshFlags.Disabled; + s_SubMeshFlagArray[subGeomIdx] = RayTracingSubMeshFlags.Disabled; } // If the material is considered opaque, every sub-mesh has to be enabled and with unique any hit calls if (!materialIsOnlyTransparent && hasTransparentSubMaterial) for (int meshIdx = 0; meshIdx < numSubMeshes; ++meshIdx) - subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.UniqueAnyHitCalls; + s_SubMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.UniqueAnyHitCalls; // We need to build the instance flag for this renderer uint instanceFlag = ComputeInstanceFlag(currentRenderer, currentRenderer.shadowCastingMode, effectsParameters, @@ -314,7 +325,7 @@ private static AccelerationStructureStatus AddRegularInstanceToRAS(RayTracingAcc // If the object was not referenced if (instanceFlag == 0) return AccelerationStructureStatus.Added; - targetRTAS.AddInstance(currentRenderer, subMeshFlags: subMeshFlagArray, enableTriangleCulling: !doubleSided, + targetRTAS.AddInstance(currentRenderer, subMeshFlags: s_SubMeshFlagArray, enableTriangleCulling: !doubleSided, mask: instanceFlag); // Indicates that a transform has changed in our scene (mesh or light) @@ -334,14 +345,14 @@ private static AccelerationStructureStatus AddVFXInstanceToRAS(RayTracingAcceler if (!effectsParameters.includeVFX) return AccelerationStructureStatus.Excluded; - currentRenderer.GetSharedMaterials(materialArray); - int numSubGeom = materialArray.Count; + currentRenderer.GetSharedMaterials(s_MaterialArray); + int numSubGeom = s_MaterialArray.Count; // If the material array is null, we are done - if (materialArray == null) return AccelerationStructureStatus.NullMaterial; + if (s_MaterialArray == null) return AccelerationStructureStatus.NullMaterial; // Let's clamp the number of sub-meshes to avoid throwing an unwanted error - numSubGeom = Mathf.Min(numSubGeom, maxNumSubMeshes); + numSubGeom = Mathf.Min(numSubGeom, k_MaxNumSubMeshes); bool materialIsOnlyTransparent = true; bool hasTransparentSubMaterial = false; @@ -349,10 +360,10 @@ private static AccelerationStructureStatus AddVFXInstanceToRAS(RayTracingAcceler bool hasAnyValidInstance = false; for (int subGeomIdx = 0; subGeomIdx < numSubGeom; ++subGeomIdx) { - if (materialArray.Count > subGeomIdx) + if (s_MaterialArray.Count > subGeomIdx) { // Grab the material for the current sub-mesh - Material currentMaterial = materialArray[subGeomIdx]; + Material currentMaterial = s_MaterialArray[subGeomIdx]; // Make sure that the material is HDRP's and non-decal if (IsValidRayTracedMaterial(currentMaterial)) @@ -367,7 +378,7 @@ private static AccelerationStructureStatus AddVFXInstanceToRAS(RayTracingAcceler ShadowCastingMode shadowCastingMode = currentMaterial.FindPass("ShadowCaster") != -1 ? ShadowCastingMode.On : ShadowCastingMode.Off; uint instanceFlag = ComputeInstanceFlag(currentRenderer, shadowCastingMode, effectsParameters, transparentMaterial, transparentMaterial); hasAnyValidInstance |= (instanceFlag != 0); - vfxSystemMasks[compactedSubGeomIndex] = instanceFlag; + s_VfxSystemMasks[compactedSubGeomIndex] = instanceFlag; compactedSubGeomIndex++; // Check if the material has changed since last time we were here @@ -384,7 +395,7 @@ private static AccelerationStructureStatus AddVFXInstanceToRAS(RayTracingAcceler if (!hasAnyValidInstance) return AccelerationStructureStatus.Added; // Add it to the acceleration structure - targetRTAS.AddVFXInstances(currentRenderer, vfxSystemMasks); + targetRTAS.AddVFXInstances(currentRenderer, s_VfxSystemMasks); // Indicates that a transform has changed in our scene (mesh or light) transformDirty |= currentRenderer.transform.hasChanged; @@ -399,13 +410,13 @@ private static void ComputeSubMeshFlag(int meshIdx, bool transparentMaterial, bo ref bool doubleSided) { // Mark the thing as valid - subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled; + s_SubMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled; // Append the additional flags depending on what kind of sub mesh this is if (!transparentMaterial && !alphaTested) - subMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.ClosestHitOnly; + s_SubMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.ClosestHitOnly; else if (transparentMaterial) - subMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.UniqueAnyHitCalls; + s_SubMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.UniqueAnyHitCalls; // Check if we want to enable double-sidedness for the mesh // (note that a mix of single and double-sided materials will result in a double-sided mesh in the AS) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs index 6e235cb047c..4a7a6ce6685 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs @@ -2,6 +2,7 @@ using UnityEngine.Rendering; using UnityEngine.Experimental.Rendering; using System.Collections.Generic; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.HighDefinition { @@ -10,41 +11,46 @@ namespace UnityEngine.Rendering.HighDefinition /// public static class CustomPassUtils { + static readonly Vector4 k_DefaultFullScreenScaleBias = new Vector4(1, 1, 0, 0); + /// /// Fullscreen scale and bias values, it is the default for functions that have scale and bias overloads. /// /// x: scaleX, y: scaleY, z: biasX, w: biasY - public static Vector4 fullScreenScaleBias = new Vector4(1, 1, 0, 0); - - static ShaderTagId[] litForwardTags = { HDShaderPassNames.s_ForwardOnlyName, HDShaderPassNames.s_ForwardName, HDShaderPassNames.s_SRPDefaultUnlitName }; - static ShaderTagId[] depthTags = { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName }; - - static ProfilingSampler downSampleSampler = new ProfilingSampler("DownSample"); - static ProfilingSampler verticalBlurSampler = new ProfilingSampler("Vertical Blur"); - static ProfilingSampler horizontalBlurSampler = new ProfilingSampler("Horizontal Blur"); - static ProfilingSampler gaussianblurSampler = new ProfilingSampler("Gaussian Blur"); - static ProfilingSampler copySampler = new ProfilingSampler("Copy"); - static ProfilingSampler renderFromCameraSampler = new ProfilingSampler("Render From Camera"); - static ProfilingSampler renderDepthFromCameraSampler = new ProfilingSampler("Render Depth"); - static ProfilingSampler renderNormalFromCameraSampler = new ProfilingSampler("Render Normal"); - static ProfilingSampler renderTangentFromCameraSampler = new ProfilingSampler("Render Tangent"); - - static MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); - static Material customPassUtilsMaterial; - static Material customPassRenderersUtilsMaterial; - - - static Dictionary gaussianWeightsCache = new Dictionary(); - - static int downSamplePassIndex; - static int verticalBlurPassIndex; - static int horizontalBlurPassIndex; - static int copyPassIndex; - static int copyDepthPassIndex; - static int depthToColorPassIndex; - static int depthPassIndex; - static int normalToColorPassIndex; - static int tangentToColorPassIndex; + [NoAutoStaticsCleanup] public static Vector4 fullScreenScaleBias = k_DefaultFullScreenScaleBias; + + static readonly ShaderTagId[] litForwardTags = { HDShaderPassNames.s_ForwardOnlyName, HDShaderPassNames.s_ForwardName, HDShaderPassNames.s_SRPDefaultUnlitName }; + static readonly ShaderTagId[] depthTags = { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName }; + + static readonly ProfilingSampler downSampleSampler = new ProfilingSampler("DownSample"); + static readonly ProfilingSampler verticalBlurSampler = new ProfilingSampler("Vertical Blur"); + static readonly ProfilingSampler horizontalBlurSampler = new ProfilingSampler("Horizontal Blur"); + static readonly ProfilingSampler gaussianblurSampler = new ProfilingSampler("Gaussian Blur"); + static readonly ProfilingSampler copySampler = new ProfilingSampler("Copy"); + static readonly ProfilingSampler renderFromCameraSampler = new ProfilingSampler("Render From Camera"); + static readonly ProfilingSampler renderDepthFromCameraSampler = new ProfilingSampler("Render Depth"); + static readonly ProfilingSampler renderNormalFromCameraSampler = new ProfilingSampler("Render Normal"); + static readonly ProfilingSampler renderTangentFromCameraSampler = new ProfilingSampler("Render Tangent"); + + static readonly MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); + + // No cleanup needed, always assigned on pipeline create by Initialize() and destroyed on pipeline dispose by Cleanup() + [NoAutoStaticsCleanup] static Material customPassUtilsMaterial; + [NoAutoStaticsCleanup] static Material customPassRenderersUtilsMaterial; + + // No cleanup needed, destroyed on pipeline dispose by Cleanup() + [NoAutoStaticsCleanup] static readonly Dictionary gaussianWeightsCache = new Dictionary(); + + // No cleanup needed, always assigned on pipeline create by Initialize() + [NoAutoStaticsCleanup] static int downSamplePassIndex; + [NoAutoStaticsCleanup] static int verticalBlurPassIndex; + [NoAutoStaticsCleanup] static int horizontalBlurPassIndex; + [NoAutoStaticsCleanup] static int copyPassIndex; + [NoAutoStaticsCleanup] static int copyDepthPassIndex; + [NoAutoStaticsCleanup] static int depthToColorPassIndex; + [NoAutoStaticsCleanup] static int depthPassIndex; + [NoAutoStaticsCleanup] static int normalToColorPassIndex; + [NoAutoStaticsCleanup] static int tangentToColorPassIndex; internal static void Initialize(HDRenderPipeline renderPipeline) { @@ -60,6 +66,9 @@ internal static void Initialize(HDRenderPipeline renderPipeline) depthPassIndex = customPassRenderersUtilsMaterial.FindPass("DepthPass"); normalToColorPassIndex = customPassRenderersUtilsMaterial.FindPass("NormalToColorPass"); tangentToColorPassIndex = customPassRenderersUtilsMaterial.FindPass("TangentToColorPass"); + + fullScreenScaleBias = k_DefaultFullScreenScaleBias; + propertyBlock.Clear(); } /// @@ -321,8 +330,8 @@ public static void GaussianBlur(in CustomPassContext ctx, RTHandle source, RTHan struct OverrideRTHandleScale : IDisposable { - // Prevent overriding multiple times in case of nested statements - static int overrideCounter = 0; + [NoAutoStaticsCleanup] // Symmetrical increment/decrement in ctor/Dispose, no need to reset + static int overrideCounter = 0; // Prevent overriding multiple times in case of nested statements CustomPassInjectionPoint injectionPoint; public OverrideRTHandleScale(in CustomPassContext ctx) @@ -788,8 +797,9 @@ public struct OverrideCameraRendering : IDisposable HDCamera overrideHDCamera; float originalAspect; - static Stack overrideCameraStack = new(); - static Stack overrideGlobalVariablesStack = new(); + // Stack is pushed/popped symmetrically by Init/Dispose so they will be empty outside the render loop, no need to reset. + [NoAutoStaticsCleanup] static readonly Stack overrideCameraStack = new(); + [NoAutoStaticsCleanup] static readonly Stack overrideGlobalVariablesStack = new(); /// /// Overrides the current camera, changing all the matrices and view parameters for the new one. @@ -936,6 +946,11 @@ internal static void Cleanup() foreach (var gaussianWeights in gaussianWeightsCache) gaussianWeights.Value.Release(); gaussianWeightsCache.Clear(); + + CoreUtils.Destroy(customPassUtilsMaterial); + customPassUtilsMaterial = null; + CoreUtils.Destroy(customPassRenderersUtilsMaterial); + customPassRenderersUtilsMaterial = null; } internal static void SetRenderTargetWithScaleBias(in CustomPassContext ctx, MaterialPropertyBlock block, RTHandle destination, Vector4 destScaleBias, ClearFlag clearFlag, int miplevel) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs index 087f51ef4cc..defb40facf4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs @@ -94,8 +94,8 @@ public Camera targetCamera internal bool useTargetCamera; // The current active custom pass volume is simply the smallest overlapping volume with the trigger transform - static HashSet m_ActivePassVolumes = new HashSet(); - static List m_OverlappingPassVolumes = new List(); + static readonly HashSet m_ActivePassVolumes = new HashSet(); + static readonly List m_OverlappingPassVolumes = new List(); static readonly Dictionary> m_GlobalCustomPasses = new(); static readonly List s_EmptyGlobalCustomPassList = new(); @@ -125,6 +125,19 @@ static List injectionPoints /// The current injection point used to render passes. Used to determine the injection point of global custom passes. internal static CustomPassInjectionPoint currentGlobalInjectionPoint; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + m_ActivePassVolumes.Clear(); + m_OverlappingPassVolumes.Clear(); + m_GlobalCustomPasses.Clear(); + m_InjectionPoints = null; + m_CurrentInjectionPointList.Clear(); + currentGlobalInjectionPoint = default; + } +#endif + /// /// Data structure used to store the global custom pass data needed for evaluation during the frame. /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DrawRenderersCustomPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DrawRenderersCustomPass.cs index f85b849f29e..eca3fc8f54b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DrawRenderersCustomPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DrawRenderersCustomPass.cs @@ -153,11 +153,8 @@ public enum OverrideMaterialMode int fadeValueId; - static ShaderTagId[] forwardShaderTags; - static ShaderTagId[] depthShaderTags; - - // Cache the shaderTagIds so we don't allocate a new array each frame - ShaderTagId[] cachedShaderTagIDs; + [NonSerialized] ShaderTagId[] m_ForwardShaderTags; + [NonSerialized] ShaderTagId[] m_DepthShaderTags; /// /// Called before the first execution of the pass occurs. @@ -175,7 +172,7 @@ protected override void Setup(ScriptableRenderContext renderContext, CommandBuff if (String.IsNullOrEmpty(overrideShaderPassName) && overrideShader != null) overrideShaderPassName = new Material(overrideShader).GetPassName(overrideShaderPassIndex); - forwardShaderTags = new ShaderTagId[] + m_ForwardShaderTags = new ShaderTagId[] { HDShaderPassNames.s_ForwardName, // HD Lit shader HDShaderPassNames.s_ForwardOnlyName, // HD Unlit shader @@ -183,7 +180,7 @@ protected override void Setup(ScriptableRenderContext renderContext, CommandBuff HDShaderPassNames.s_EmptyName, // Add an empty slot for the override material }; - depthShaderTags = new ShaderTagId[] + m_DepthShaderTags = new ShaderTagId[] { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName, @@ -205,9 +202,9 @@ protected override void AggregateCullingParameters(ref ScriptableCullingParamete ShaderTagId[] GetShaderTagIds() { if (shaderPass == ShaderPass.DepthPrepass) - return depthShaderTags; + return m_DepthShaderTags; else - return forwardShaderTags; + return m_ForwardShaderTags; } /// diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/CaptureSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/CaptureSettings.cs index 631e80ba60a..fae77920173 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/CaptureSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/CaptureSettings.cs @@ -1,4 +1,5 @@ using System; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.HighDefinition { @@ -50,7 +51,7 @@ internal enum ObsoleteCaptureSettingsOverrides internal class ObsoleteCaptureSettings { /// Obsolete - public static ObsoleteCaptureSettings @default = new ObsoleteCaptureSettings(); + [NoAutoStaticsCleanup] public static ObsoleteCaptureSettings @default = new ObsoleteCaptureSettings(); /// Obsolete public ObsoleteCaptureSettingsOverrides overrides; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs index 4c25830bbe7..b0bd9feed0a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs @@ -962,7 +962,7 @@ public DebuggerGroup[] Keys var groupIndexes = attributes.Values.Where(a => a != null).Select(a => a.group).Distinct(); foreach (int groupIndex in groupIndexes) - groups.Add(new DebuggerGroup(FrameSettingsHistory.foldoutNames[groupIndex], attributes?.Where(pair => pair.Value?.group == groupIndex)?.OrderBy(pair => pair.Value.orderInGroup).Select(kvp => new DebuggerEntry(Enum.GetName(typeof(FrameSettingsField), kvp.Key), m_FrameSettings.bitDatas[(uint)kvp.Key])).ToArray())); + groups.Add(new DebuggerGroup(FrameSettingsHistory.k_FoldoutNames[groupIndex], attributes?.Where(pair => pair.Value?.group == groupIndex)?.OrderBy(pair => pair.Value.orderInGroup).Select(kvp => new DebuggerEntry(Enum.GetName(typeof(FrameSettingsField), kvp.Key), m_FrameSettings.bitDatas[(uint)kvp.Key])).ToArray())); groups.Add(new DebuggerGroup("Bits without attribute", noAttribute.Where(fs => fs != FrameSettingsField.None)?.Select(fs => new DebuggerEntry(Enum.GetName(typeof(FrameSettingsField), fs), m_FrameSettings.bitDatas[(uint)fs])).ToArray())); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsDefaults.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsDefaults.cs index 426b56a8a1c..b99a4fc0dbb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsDefaults.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsDefaults.cs @@ -4,7 +4,7 @@ namespace UnityEngine.Rendering.HighDefinition { static class FrameSettingsDefaults { - private static uint[] s_CameraDefaultbitDatas = new uint[] + private static readonly uint[] s_CameraDefaultbitDatas = new uint[] { (uint)FrameSettingsField.ShadowMaps, (uint)FrameSettingsField.ContactShadows, @@ -89,7 +89,7 @@ static class FrameSettingsDefaults // (uint)FullResolutionCloudsForSky }; - private static uint[] s_BakedOrCustomReflectionbitDatas = new uint[] + private static readonly uint[] s_BakedOrCustomReflectionbitDatas = new uint[] { (uint)FrameSettingsField.ShadowMaps, //(uint)FrameSettingsField.ContactShadow, @@ -146,7 +146,7 @@ static class FrameSettingsDefaults // (uint)FullResolutionCloudsForSky }; - private static uint[] s_RealtimeReflectionbitDatas = new uint[] + private static readonly uint[] s_RealtimeReflectionbitDatas = new uint[] { (uint)FrameSettingsField.ShadowMaps, (uint)FrameSettingsField.ContactShadows, 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 be96530667a..a411f4ab5e1 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 @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using System.Linq; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.HighDefinition { @@ -28,17 +29,20 @@ internal interface IFrameSettingsHistoryContainer : IDebugData struct FrameSettingsHistory { - internal static readonly string[] foldoutNames = { "Rendering", "Lighting", "Async Compute", "Light Loop" }; - static readonly string[] columnNames = { "Debug", "Sanitized", "Overridden", "Default" }; - static readonly string[] columnTooltips = + internal static readonly string[] k_FoldoutNames = { "Rendering", "Lighting", "Async Compute", "Light Loop" }; + static readonly string[] k_ColumnNames = { "Debug", "Sanitized", "Overridden", "Default" }; + static readonly string[] k_ColumnTooltips = { "Displays Frame Setting values you can modify for the selected Camera.", "Displays the Frame Setting values that the selected Camera uses after Unity checks to see if your HDRP Asset supports them.", "Displays the Frame Setting values that the selected Camera overrides.", "Displays the default Frame Setting values in your current HDRP Asset." }; - static readonly Dictionary attributes; - static Dictionary>> attributesGroup = new Dictionary>>(); + + [NoAutoStaticsCleanup] // Reflection data that only depends on FrameSettingsField and FrameSettingsFieldAttribute, doesn't need to be cleared. + static readonly Dictionary s_Attributes = new(); + [NoAutoStaticsCleanup] // Another cache-like data structure constructed from s_Attributes, doesn't need to be cleared. + static readonly Dictionary>> s_AttributesGroup = new(); // due to strange management of Scene view cameras, all camera of type Scene will share same FrameSettingsHistory #if UNITY_EDITOR @@ -80,7 +84,7 @@ Action IDebugData.GetReset() internal static IFrameSettingsHistoryContainer sceneViewFrameSettingsContainer = new MinimalHistoryContainer(); #endif - internal static HashSet containers = new HashSet(); + internal static readonly HashSet containers = new HashSet(); public FrameSettingsRenderType defaultType; public FrameSettings overridden; @@ -111,16 +115,23 @@ public static bool enabled } } +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + containers.Clear(); + s_PossiblyInUse = false; + } +#endif + /// Initialize data for FrameSettings panel of DebugMenu construction. static FrameSettingsHistory() { - attributes = new Dictionary(); - attributesGroup = new Dictionary>>(); Dictionary frameSettingsEnumNameMap = FrameSettingsFieldAttribute.GetEnumNameMap(); Type type = typeof(FrameSettingsField); foreach (FrameSettingsField enumVal in frameSettingsEnumNameMap.Keys) { - attributes[enumVal] = type.GetField(frameSettingsEnumNameMap[enumVal]).GetCustomAttribute(); + s_Attributes[enumVal] = type.GetField(frameSettingsEnumNameMap[enumVal]).GetCustomAttribute(); } } @@ -253,9 +264,9 @@ static DebugUI.HistoryEnumField GenerateHistoryEnumField(RenderingPathFrameSetti static ObservableList GenerateHistoryArea(IFrameSettingsHistoryContainer frameSettingsContainer, int groupIndex) { - if (!attributesGroup.ContainsKey(groupIndex) || attributesGroup[groupIndex] == null) - attributesGroup[groupIndex] = attributes?.Where(pair => pair.Value?.group == groupIndex)?.OrderBy(pair => pair.Value.orderInGroup); - if (!attributesGroup.ContainsKey(groupIndex)) + if (!s_AttributesGroup.ContainsKey(groupIndex) || s_AttributesGroup[groupIndex] == null) + s_AttributesGroup[groupIndex] = s_Attributes?.Where(pair => pair.Value?.group == groupIndex)?.OrderBy(pair => pair.Value.orderInGroup); + if (!s_AttributesGroup.ContainsKey(groupIndex)) throw new ArgumentException("Unknown groupIndex"); var area = new ObservableList(); @@ -263,7 +274,7 @@ static DebugUI.HistoryEnumField GenerateHistoryEnumField(RenderingPathFrameSetti var defaulRenderingPathFrameSettings = GraphicsSettings.GetRenderPipelineSettings(); - foreach (var field in attributesGroup[groupIndex]) + foreach (var field in s_AttributesGroup[groupIndex]) { switch (field.Value.type) { @@ -296,11 +307,11 @@ internal static DebugUI.Widget[] GenerateFrameSettingsPanelContent(IFrameSetting if (frameSettingsContainer == null) return Array.Empty(); - var panelContent = new DebugUI.Widget[foldoutNames.Length]; - for (int index = 0; index < foldoutNames.Length; ++index) + var panelContent = new DebugUI.Widget[k_FoldoutNames.Length]; + for (int index = 0; index < k_FoldoutNames.Length; ++index) { - panelContent[index] = new DebugUI.Foldout(foldoutNames[index], - GenerateHistoryArea(frameSettingsContainer, index), columnNames, columnTooltips); + panelContent[index] = new DebugUI.Foldout(k_FoldoutNames[index], + GenerateHistoryArea(frameSettingsContainer, index), k_ColumnNames, k_ColumnTooltips); } return panelContent; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs index 95b8b940828..a8f6dbbd461 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs @@ -3,6 +3,7 @@ using System.Linq; using UnityEngine.Experimental.Rendering; using System.Text.RegularExpressions; +using Unity.Scripting.LifecycleManagement; #if UNITY_EDITOR using UnityEditor.SceneManagement; @@ -52,10 +53,9 @@ public static PerObjectData GetRendererConfiguration(bool apv, bool shadowMask) /// Default HDAdditionalCameraData static internal HDAdditionalCameraData s_DefaultHDAdditionalCameraData { get { return ComponentSingleton.instance; } } - static List m_TempCustomPassVolumeList = new List(); - static Texture3D m_ClearTexture3D; static RTHandle m_ClearTexture3DRTH; + /// /// Default 1x1x1 3D texture initialized with Color.clear. /// @@ -1016,13 +1016,16 @@ internal static bool WillCustomPassBeExecuted(HDCamera hdCamera, CustomPassInjec return false; bool executed = false; - CustomPassVolume.GetActivePassVolumes(injectionPoint, m_TempCustomPassVolumeList); - foreach (var customPassVolume in m_TempCustomPassVolumeList) + using (ListPool.Get(out var tempCustomPassVolumeList)) { - if (customPassVolume == null) - return false; + CustomPassVolume.GetActivePassVolumes(injectionPoint, tempCustomPassVolumeList); + foreach (var customPassVolume in tempCustomPassVolumeList) + { + if (customPassVolume == null) + return false; - executed |= customPassVolume.WillExecuteInjectionPoint(hdCamera); + executed |= customPassVolume.WillExecuteInjectionPoint(hdCamera); + } } return executed; @@ -1205,7 +1208,8 @@ internal static HDAdditionalCameraData TryGetAdditionalCameraDataOrDefault(Camer return s_DefaultHDAdditionalCameraData; } - static Dictionary graphicsFormatSizeCache = new Dictionary + [NoAutoStaticsCleanup] // Cache that is populated based on Enum.ToString(), no need to clear + static readonly Dictionary graphicsFormatSizeCache = new Dictionary { // Init some default format so we don't allocate more memory on the first frame. {GraphicsFormat.R8G8B8A8_UNorm, 4}, From fd32284978967cc5bfae05b4b75489a2a0468298 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Wed, 22 Apr 2026 16:01:12 +0000 Subject: [PATCH 31/56] Reset static variables for CoreCLR / Fast Enter Play Mode (SRP Core Team, render-pipelines.universal package) --- .../Data/UniversalRenderPipelineAsset.cs | 4 +- .../Decal/DBuffer/DBufferRenderPass.cs | 4 +- .../Runtime/Deprecated.cs | 11 +- .../Runtime/NoAllocUtils.cs | 4 +- .../Runtime/Passes/GBufferPass.cs | 27 ++-- .../Runtime/Passes/ScriptableRenderPass.cs | 4 +- .../Runtime/RTHandleUtils.cs | 16 ++- .../Runtime/RenderTargetBufferSystem.cs | 123 ------------------ .../Runtime/RenderTargetBufferSystem.cs.meta | 11 -- .../FullScreenPassRendererFeature.cs | 18 +-- .../Runtime/RenderingUtils.cs | 35 +++-- .../Runtime/ScriptableRenderer.cs | 13 +- .../Runtime/ShaderData.cs | 9 ++ .../Runtime/UniversalAdditionalCameraData.cs | 25 ++-- .../Runtime/UniversalCameraHistory.cs | 5 + .../Runtime/UniversalRenderPipeline.cs | 66 ++++++---- .../Runtime/UniversalRenderPipelineCore.cs | 27 ++-- .../Runtime/UniversalRendererRenderGraph.cs | 31 +++-- 18 files changed, 186 insertions(+), 247 deletions(-) delete mode 100644 Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs delete mode 100644 Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs.meta diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs index 5f531d53921..79fcdbcda9d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs @@ -981,7 +981,7 @@ string RendererDataDisplayName(ScriptableRendererData data) } #endif - private static GraphicsFormat[][] s_LightCookieFormatList = new GraphicsFormat[][] + private static readonly GraphicsFormat[][] k_LightCookieFormatList = new GraphicsFormat[][] { /* Grayscale Low */ new GraphicsFormat[] {GraphicsFormat.R8_UNorm}, /* Grayscale High*/ new GraphicsFormat[] {GraphicsFormat.R16_UNorm}, @@ -995,7 +995,7 @@ internal GraphicsFormat additionalLightsCookieFormat get { GraphicsFormat result = GraphicsFormat.None; - foreach (var format in s_LightCookieFormatList[(int)m_AdditionalLightsCookieFormat]) + foreach (var format in k_LightCookieFormatList[(int)m_AdditionalLightsCookieFormat]) { if (SystemInfo.IsFormatSupported(format, GraphicsFormatUsage.Render)) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs index b0d36283ac3..2951b6fd637 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs @@ -14,8 +14,8 @@ public DecalDrawDBufferSystem(DecalEntityManager entityManager) : base("DecalDra internal class DBufferRenderPass : ScriptableRenderPass { - internal static string[] s_DBufferNames = { "_DBufferTexture0", "_DBufferTexture1", "_DBufferTexture2", "_DBufferTexture3" }; - internal static string s_DBufferDepthName = "DBufferDepth"; + internal static readonly string[] s_DBufferNames = { "_DBufferTexture0", "_DBufferTexture1", "_DBufferTexture2", "_DBufferTexture3" }; + internal static readonly string s_DBufferDepthName = "DBufferDepth"; static readonly int s_SSAOTextureID = Shader.PropertyToID("_ScreenSpaceOcclusionTexture"); private DecalDrawDBufferSystem m_DrawSystem; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Deprecated.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Deprecated.cs index 5b4dd85751d..dea5c0c3653 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Deprecated.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Deprecated.cs @@ -2,6 +2,7 @@ // way to being deprecated and removed in future releases using System; using System.ComponentModel; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.Universal { @@ -24,14 +25,16 @@ public partial class AdditionalLightsShadowCasterPass /// The ID for the additional shadows buffer ID. /// This has been deprecated. Shadow slice matrix is now passed to the GPU using an entry in buffer m_AdditionalLightsWorldToShadow_SSBO. /// - [Obsolete("AdditionalLightsShadowCasterPass.m_AdditionalShadowsBufferId was deprecated. Shadow slice matrix is now passed to the GPU using an entry in buffer m_AdditionalLightsWorldToShadow_SSBO #from(2021.1) #breakingFrom(2023.1)", true)] + [Obsolete("AdditionalLightsShadowCasterPass.m_AdditionalShadowsBufferId was deprecated. Shadow slice matrix is now passed to the GPU using an entry in buffer m_AdditionalLightsWorldToShadow_SSBO. Fast Enter Playmode is not supported. #from(2021.1) #breakingFrom(2023.1)", true)] + [NoAutoStaticsCleanup] // Obsolete API not supported public static int m_AdditionalShadowsBufferId; /// /// The ID for the additional shadows buffer ID. /// This has been deprecated. hadow slice index is now passed to the GPU using last member of an entry in buffer m_AdditionalShadowParams_SSBO. /// - [Obsolete("AdditionalLightsShadowCasterPass.m_AdditionalShadowsIndicesId was deprecated. Shadow slice index is now passed to the GPU using last member of an entry in buffer m_AdditionalShadowParams_SSBO #from(2021.1) #breakingFrom(2023.1)", true)] + [Obsolete("AdditionalLightsShadowCasterPass.m_AdditionalShadowsIndicesId was deprecated. Shadow slice index is now passed to the GPU using last member of an entry in buffer m_AdditionalShadowParams_SSBO #from(2021.1). Fast Enter Playmode is not supported. #breakingFrom(2023.1)", true)] + [NoAutoStaticsCleanup] // Obsolete API not supported public static int m_AdditionalShadowsIndicesId; } } @@ -189,7 +192,7 @@ public TextureResources textures return m_Textures; } } - + /// /// Controls when URP renders via an intermediate texture. /// @@ -603,7 +606,7 @@ public sealed class ShaderResources [Obsolete("Moved to UniversalRenderPipelineRuntimeShaders on GraphicsSettings. #from(2023.3)")] public Shader dataDrivenLensFlare; } - + partial class UniversalRenderPipelineGlobalSettings { #pragma warning disable 0414 diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/NoAllocUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/NoAllocUtils.cs index 49a78105b08..582a674dd4a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/NoAllocUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/NoAllocUtils.cs @@ -10,8 +10,8 @@ internal struct Sorting { // Add profling samplers to sorts as they often are a bottleneck when scaling things up. // By default avoid sampling recursion, but these can be used externally as well. - static public ProfilingSampler s_QuickSortSampler = new ProfilingSampler("QuickSort"); - static public ProfilingSampler s_InsertionSortSampler = new ProfilingSampler("InsertionSort"); + static public readonly ProfilingSampler s_QuickSortSampler = new ProfilingSampler("QuickSort"); + static public readonly ProfilingSampler s_InsertionSortSampler = new ProfilingSampler("InsertionSort"); public static void QuickSort(T[] data, Func compare) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs index 57a82d01b54..e26100238fe 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs @@ -1,5 +1,6 @@ using System; using Unity.Collections; +using Unity.Scripting.LifecycleManagement; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal.Internal @@ -20,8 +21,16 @@ internal class GBufferPass : ScriptableRenderPass DeferredLights m_DeferredLights; - static ShaderTagId[] s_ShaderTagValues; - static RenderStateBlock[] s_RenderStateBlocks; + static readonly ShaderTagId[] s_ShaderTagValues = { + s_ShaderTagLit, + s_ShaderTagSimpleLit, + s_ShaderTagUnlit, + s_ShaderTagComplexLit, + s_ShaderTagBakedLit, + new ShaderTagId() // Special catch all case for materials where UniversalMaterialType is not defined or the tag value doesn't match anything we know. + }; + + RenderStateBlock[] m_RenderStateBlocks; FilteringSettings m_FilteringSettings; RenderStateBlock m_RenderStateBlock; @@ -39,17 +48,7 @@ public GBufferPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, Layer m_RenderStateBlock.stencilReference = stencilReference; m_RenderStateBlock.mask = RenderStateMask.Stencil; - s_ShaderTagValues ??= new ShaderTagId[] - { - s_ShaderTagLit, - s_ShaderTagSimpleLit, - s_ShaderTagUnlit, - s_ShaderTagComplexLit, - s_ShaderTagBakedLit, - new ShaderTagId() // Special catch all case for materials where UniversalMaterialType is not defined or the tag value doesn't match anything we know. - }; - - s_RenderStateBlocks ??= new RenderStateBlock[] + m_RenderStateBlocks = new RenderStateBlock[] { DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialLit), DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialSimpleLit), @@ -123,7 +122,7 @@ private void InitRendererLists( ref PassData passData, ScriptableRenderContext c #endif NativeArray tagValues = new NativeArray(s_ShaderTagValues, Allocator.Temp); - NativeArray stateBlocks = new NativeArray(s_RenderStateBlocks, Allocator.Temp); + NativeArray stateBlocks = new NativeArray(m_RenderStateBlocks, Allocator.Temp); var param = new RendererListParams(renderingData.cullResults, drawingSettings, filterSettings) { tagValues = tagValues, diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs index 0411d478b4c..f69112cd62f 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScriptableRenderPass.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using Unity.Collections; +using Unity.Scripting.LifecycleManagement; using UnityEngine.Scripting.APIUpdating; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; @@ -174,7 +175,8 @@ internal enum FramebufferFetchEvent internal static class RenderPassEventsEnumValues { // we cache the values in this array at construction time to avoid runtime allocations, which we would cause if we accessed valuesInternal directly - public static int[] values; + [NoAutoStaticsCleanup] // Clearing the array is not necessary when entering play mode because it's reflection data. + public static readonly int[] values; static RenderPassEventsEnumValues() { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs index 7c7d394e81b..d9343f21945 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs @@ -20,10 +20,20 @@ internal class RTHandleResourcePool protected static int s_CurrentStaleResourceCount = 0; // Keep stale resources alive for 3 frames - protected static int s_StaleResourceLifetime = 3; + protected const int k_StaleResourceLifetime = 3; // Store max 32 rtHandles // 1080p * 32bpp * 32 = 265.4mb - protected static int s_StaleResourceMaxCapacity = 32; + const int k_StaleResourceMaxCapacityDefault = 32; + protected static int s_StaleResourceMaxCapacity = k_StaleResourceMaxCapacityDefault; + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + s_CurrentStaleResourceCount = 0; + s_StaleResourceMaxCapacity = k_StaleResourceMaxCapacityDefault; + } +#endif /// /// Controls the resource pool's max stale resource capacity. @@ -103,7 +113,7 @@ static protected bool ShouldReleaseResource(int lastUsedFrameIndex, int currentF // We need to have a delay of a few frames before releasing resources for good. // Indeed, when having multiple off-screen cameras, they are rendered in a separate SRP render call and thus with a different frame index than main camera // This causes texture to be deallocated/reallocated every frame if the two cameras don't need the same buffers. - return (lastUsedFrameIndex + s_StaleResourceLifetime) < currentFrameIndex; + return (lastUsedFrameIndex + k_StaleResourceLifetime) < currentFrameIndex; } // Release resources that are not used in last couple frames. diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs deleted file mode 100644 index 115b41af049..00000000000 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using UnityEngine.Experimental.Rendering; - -namespace UnityEngine.Rendering.Universal.Internal -{ - internal sealed class RenderTargetBufferSystem - { - struct SwapBuffer - { - public RTHandle rtMSAA; - public RTHandle rtResolve; - public string name; - public int msaa; - } - SwapBuffer m_A, m_B; - static bool m_AisBackBuffer = true; - - static RenderTextureDescriptor m_Desc; - FilterMode m_FilterMode; - bool m_AllowMSAA = true; - - ref SwapBuffer backBuffer { get { return ref m_AisBackBuffer ? ref m_A : ref m_B; } } - ref SwapBuffer frontBuffer { get { return ref m_AisBackBuffer ? ref m_B : ref m_A; } } - - public RenderTargetBufferSystem(string name) - { - m_A.name = name + "A"; - m_B.name = name + "B"; - } - - public void Dispose() - { - m_A.rtMSAA?.Release(); - m_B.rtMSAA?.Release(); - m_A.rtResolve?.Release(); - m_B.rtResolve?.Release(); - } - - public RTHandle PeekBackBuffer() - { - return (m_AllowMSAA && backBuffer.msaa > 1) ? backBuffer.rtMSAA : backBuffer.rtResolve; - } - - public RTHandle GetBackBuffer(CommandBuffer cmd) - { - ReAllocate(cmd); - return PeekBackBuffer(); - } - - public RTHandle GetFrontBuffer(CommandBuffer cmd) - { - if (!m_AllowMSAA && frontBuffer.msaa > 1) - frontBuffer.msaa = 1; - - ReAllocate(cmd); - - return (m_AllowMSAA && frontBuffer.msaa > 1) ? frontBuffer.rtMSAA : frontBuffer.rtResolve; - } - - public void Swap() - { - m_AisBackBuffer = !m_AisBackBuffer; - } - - void ReAllocate(CommandBuffer cmd) - { - var desc = m_Desc; - - desc.msaaSamples = m_A.msaa; - if (desc.msaaSamples > 1) - RenderingUtils.ReAllocateHandleIfNeeded(ref m_A.rtMSAA, desc, m_FilterMode, TextureWrapMode.Clamp, name: m_A.name); - - desc.msaaSamples = m_B.msaa; - if (desc.msaaSamples > 1) - RenderingUtils.ReAllocateHandleIfNeeded(ref m_B.rtMSAA, desc, m_FilterMode, TextureWrapMode.Clamp, name: m_B.name); - - desc.msaaSamples = 1; - RenderingUtils.ReAllocateHandleIfNeeded(ref m_A.rtResolve, desc, m_FilterMode, TextureWrapMode.Clamp, name: m_A.name); - RenderingUtils.ReAllocateHandleIfNeeded(ref m_B.rtResolve, desc, m_FilterMode, TextureWrapMode.Clamp, name: m_B.name); - cmd.SetGlobalTexture(m_A.name, m_A.rtResolve); - cmd.SetGlobalTexture(m_B.name, m_B.rtResolve); - } - - public void Clear() - { - m_AisBackBuffer = true; - m_AllowMSAA = m_A.msaa > 1 || m_B.msaa > 1; - } - - public void SetCameraSettings(RenderTextureDescriptor desc, FilterMode filterMode) - { - desc.depthStencilFormat = GraphicsFormat.None; - m_Desc = desc; - m_FilterMode = filterMode; - - m_A.msaa = m_Desc.msaaSamples; - m_B.msaa = m_Desc.msaaSamples; - - if (m_Desc.msaaSamples > 1) - EnableMSAA(true); - } - - public RTHandle GetBufferA() - { - return (m_AllowMSAA && m_A.msaa > 1) ? m_A.rtMSAA : m_A.rtResolve; - } - - public void EnableMSAA(bool enable) - { - m_AllowMSAA = enable; - if (enable) - { - m_A.msaa = m_Desc.msaaSamples; - m_B.msaa = m_Desc.msaaSamples; - } - } - } -} diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs.meta b/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs.meta deleted file mode 100644 index 26e58d36a40..00000000000 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4e520775f70c7bb40bab742eb999d0e4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/FullScreenPassRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/FullScreenPassRendererFeature.cs index a127ee66a2a..f1bc6973dbc 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/FullScreenPassRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/FullScreenPassRendererFeature.cs @@ -135,7 +135,7 @@ internal class FullScreenRenderPass : ScriptableRenderPass private bool m_FetchActiveColor; private bool m_BindDepthStencilAttachment; - private static MaterialPropertyBlock s_SharedPropertyBlock = new MaterialPropertyBlock(); + private readonly MaterialPropertyBlock m_MaterialPropertyBlock = new MaterialPropertyBlock(); public FullScreenRenderPass(string passName) { @@ -150,16 +150,16 @@ public void SetupMembers(Material material, int passIndex, bool fetchActiveColor m_BindDepthStencilAttachment = bindDepthStencilAttachment; } - private static void ExecuteMainPass(RasterCommandBuffer cmd, RTHandle sourceTexture, Material material, int passIndex, Vector4 blitScaleBias) + private static void ExecuteMainPass(RasterCommandBuffer cmd, MaterialPropertyBlock mbp, RTHandle sourceTexture, Material material, int passIndex, Vector4 blitScaleBias) { - s_SharedPropertyBlock.Clear(); + mbp.Clear(); if (sourceTexture != null) - s_SharedPropertyBlock.SetTexture(ShaderPropertyId.blitTexture, sourceTexture); + mbp.SetTexture(ShaderPropertyId.blitTexture, sourceTexture); // We need to set the "_BlitScaleBias" uniform for user materials with shaders relying on core Blit.hlsl to work - s_SharedPropertyBlock.SetVector(ShaderPropertyId.blitScaleBias, blitScaleBias); + mbp.SetVector(ShaderPropertyId.blitScaleBias, blitScaleBias); - cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Triangles, 3, 1, s_SharedPropertyBlock); + cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Triangles, 3, 1, mbp); } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) @@ -203,10 +203,11 @@ private void AddFullscreenRenderPassInputPass(RenderGraph renderGraph, Universal using (var builder = renderGraph.AddRasterRenderPass(passName, out var passData, profilingSampler)) { passData.material = m_Material; + passData.materialPropertyBlock = m_MaterialPropertyBlock; passData.passIndex = m_PassIndex; passData.source = source; - passData.destination = destination; + passData.destination = destination; if (passData.source.IsValid()) builder.UseTexture(passData.source, AccessFlags.Read); @@ -255,13 +256,14 @@ private void AddFullscreenRenderPassInputPass(RenderGraph renderGraph, Universal builder.SetRenderFunc(static (MainPassData data, RasterGraphContext rgContext) => { Vector4 scaleBias = RenderingUtils.GetFinalBlitScaleBias(rgContext, in data.source, in data.destination); - ExecuteMainPass(rgContext.cmd, data.source, data.material, data.passIndex, scaleBias); + ExecuteMainPass(rgContext.cmd, data.materialPropertyBlock, data.source, data.material, data.passIndex, scaleBias); }); } } private class MainPassData { internal Material material; + internal MaterialPropertyBlock materialPropertyBlock; internal int passIndex; internal TextureHandle source; internal TextureHandle destination; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs index 3daca3a2cd4..9dab4b7974d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs @@ -15,7 +15,7 @@ namespace UnityEngine.Rendering.Universal /// public static class RenderingUtils { - static List m_LegacyShaderPassNames = new List + static readonly ShaderTagId[] s_LegacyShaderPassNames = { new ShaderTagId("Always"), new ShaderTagId("ForwardBase"), @@ -25,7 +25,7 @@ public static class RenderingUtils new ShaderTagId("VertexLM"), }; - static AttachmentDescriptor s_EmptyAttachment = new AttachmentDescriptor(GraphicsFormat.None); + static readonly AttachmentDescriptor s_EmptyAttachment = new AttachmentDescriptor(GraphicsFormat.None); internal static AttachmentDescriptor emptyAttachment { get @@ -34,6 +34,17 @@ internal static AttachmentDescriptor emptyAttachment } } +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + CoreUtils.Destroy(s_FullscreenMesh); + s_FullscreenMesh = null; + CoreUtils.Destroy(s_ErrorMaterial); + s_ErrorMaterial = null; + } +#endif + static Mesh s_FullscreenMesh = null; /// @@ -214,15 +225,15 @@ internal static void SetupOffscreenUIViewportParams(Material material, ref Rect internal static void CreateRendererParamsObjectsWithError(ref CullingResults cullResults, Camera camera, FilteringSettings filterSettings, SortingCriteria sortFlags, ref RendererListParams param) { SortingSettings sortingSettings = new SortingSettings(camera) { criteria = sortFlags }; - DrawingSettings errorSettings = new DrawingSettings(m_LegacyShaderPassNames[0], sortingSettings) + DrawingSettings errorSettings = new DrawingSettings(s_LegacyShaderPassNames[0], sortingSettings) { perObjectData = PerObjectData.None, overrideMaterial = errorMaterial, overrideMaterialPassIndex = 0 }; - for (int i = 1; i < m_LegacyShaderPassNames.Count; ++i) - errorSettings.SetShaderPassName(i, m_LegacyShaderPassNames[i]); - + for (int i = 1; i < s_LegacyShaderPassNames.Length; ++i) + errorSettings.SetShaderPassName(i, s_LegacyShaderPassNames[i]); + param = new RendererListParams(cullResults, errorSettings, filterSettings); } @@ -251,8 +262,8 @@ internal static void DrawRendererListObjectsWithError(RasterCommandBuffer cmd, r cmd.DrawRendererList(rl); } - static ShaderTagId[] s_ShaderTagValues = new ShaderTagId[1]; - static RenderStateBlock[] s_RenderStateBlocks = new RenderStateBlock[1]; + static readonly ShaderTagId[] s_ShaderTagValues = new ShaderTagId[1]; + static readonly RenderStateBlock[] s_RenderStateBlocks = new RenderStateBlock[1]; // Create a RendererList using a RenderStateBlock override is quite common so we have this optimized utility function for it internal static void CreateRendererListWithRenderStateBlock(RenderGraph renderGraph, ref CullingResults cullResults, DrawingSettings ds, FilteringSettings fs, RenderStateBlock rsb, ref RendererListHandle rl) { @@ -270,11 +281,11 @@ internal static void CreateRendererListWithRenderStateBlock(RenderGraph renderGr } // Caches render texture format support. SystemInfo.SupportsRenderTextureFormat allocates memory due to boxing. - static Dictionary m_RenderTextureFormatSupport = new Dictionary(); + static readonly Dictionary s_RenderTextureFormatSupport = new Dictionary(); internal static void ClearSystemInfoCache() { - m_RenderTextureFormatSupport.Clear(); + s_RenderTextureFormatSupport.Clear(); } /// @@ -285,10 +296,10 @@ internal static void ClearSystemInfoCache() /// Returns true if the graphics card supports the given RenderTextureFormat public static bool SupportsRenderTextureFormat(RenderTextureFormat format) { - if (!m_RenderTextureFormatSupport.TryGetValue(format, out var support)) + if (!s_RenderTextureFormatSupport.TryGetValue(format, out var support)) { support = SystemInfo.SupportsRenderTextureFormat(format); - m_RenderTextureFormatSupport.Add(format, support); + s_RenderTextureFormatSupport.Add(format, support); } return support; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs index 132218f3d0b..d193bf117bc 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs @@ -165,6 +165,14 @@ public class RenderingFeatures /// internal static ScriptableRenderer current = null; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + current = null; + } +#endif + internal static void SetCameraMatrices(RasterCommandBuffer cmd, UniversalCameraData cameraData, bool setInverseMatrices, bool isTargetFlipped) { #if ENABLE_VR && ENABLE_XR_MODULE @@ -466,8 +474,9 @@ internal virtual void UpdateSupportedRenderingFeatures() { } ContextContainer m_frameData = new(); internal ContextContainer frameData => m_frameData; - private static Plane[] s_Planes = new Plane[6]; - private static Vector4[] s_VectorPlanes = new Vector4[6]; + // Scratch buffers for SetPerCameraClippingPlaneProperties to avoid per-call allocations + private static readonly Plane[] s_Planes = new Plane[6]; + private static readonly Vector4[] s_VectorPlanes = new Vector4[6]; /// /// In URP RenderGraph (likely not in Compatibility Mode), this returns if the pipeline will actually perform depth priming. diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderData.cs index f88f6882bc8..a987f13229e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderData.cs @@ -6,6 +6,15 @@ namespace UnityEngine.Rendering.Universal class ShaderData : IDisposable { static ShaderData m_Instance = null; + +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + m_Instance = null; + } +#endif + ComputeBuffer m_LightDataBuffer = null; ComputeBuffer m_LightIndicesBuffer = null; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs index 0d0adaae4ce..4dcf26d61bd 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Unity.Scripting.LifecycleManagement; using UnityEditor; using UnityEngine.Serialization; using UnityEngine.Assertions; @@ -353,7 +354,8 @@ internal static void GetVolumeLayerMaskAndTrigger(this Camera camera, UniversalA static class CameraTypeUtility { - static string[] s_CameraTypeNames = Enum.GetNames(typeof(CameraRenderType)).ToArray(); + [NoAutoStaticsCleanup] // Reflection data cache, no need to clear. + static readonly string[] s_CameraTypeNames = Enum.GetNames(typeof(CameraRenderType)); public static string GetName(this CameraRenderType type) { @@ -492,18 +494,6 @@ public partial class UniversalAdditionalCameraData : MonoBehaviour, ISerializati [SerializeField] internal TemporalAA.Settings m_TaaSettings = TemporalAA.Settings.Create(); - static UniversalAdditionalCameraData s_DefaultAdditionalCameraData = null; - internal static UniversalAdditionalCameraData defaultAdditionalCameraData - { - get - { - if (s_DefaultAdditionalCameraData == null) - s_DefaultAdditionalCameraData = new UniversalAdditionalCameraData(); - - return s_DefaultAdditionalCameraData; - } - } - internal Camera camera { get @@ -753,6 +743,15 @@ public bool requiresVolumeFrameworkUpdate /// private static List s_CachedVolumeStacks; +#if UNITY_EDITOR + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + static void ResetStaticsOnLoad() + { + s_CachedVolumeStacks?.Clear(); + s_CachedVolumeStacks = null; + } +#endif + /// /// Returns the current volume stack used by this camera. /// diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalCameraHistory.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalCameraHistory.cs index 6be42859d26..64bdf3d82f1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalCameraHistory.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalCameraHistory.cs @@ -1,5 +1,6 @@ using System; using Unity.Mathematics; +using Unity.Scripting.LifecycleManagement; namespace UnityEngine.Rendering.Universal { @@ -15,9 +16,13 @@ public class UniversalCameraHistory : ICameraHistoryReadAccess, ICameraHistoryWr /// const int k_ValidVersionCount = 2; // current frame + previous frame + // Static s_TypeCount and TypeId.value fields don't need to be reset when entering playmode. + // s_TypeCount is only incremented by the static initialization of TypeId.value. + [NoAutoStaticsCleanup] private static uint s_TypeCount = 0; private static class TypeId { + [NoAutoStaticsCleanup] public static uint value = s_TypeCount++; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index a4866eba9ae..d19fcb71e9a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -2,6 +2,7 @@ using Unity.Collections; using System.Collections.Generic; using System.Reflection; +using Unity.Scripting.LifecycleManagement; #if UNITY_EDITOR using UnityEditor; using UnityEditor.Rendering.Universal; @@ -95,7 +96,7 @@ public class CameraMetadataCacheEntry public ProfilingSampler sampler; } - static Dictionary s_MetadataCache = new(); + static readonly Dictionary s_MetadataCache = new(); static readonly CameraMetadataCacheEntry k_NoAllocEntry = new() { sampler = new ProfilingSampler("Unknown") }; @@ -119,6 +120,11 @@ public static CameraMetadataCacheEntry GetCached(Camera camera) return result; #endif } + + public static void Clear() + { + s_MetadataCache.Clear(); + } } internal static class Profiling @@ -242,24 +248,26 @@ internal static bool UseDynamicBranchFogKeyword() /// public override RenderPipelineGlobalSettings defaultSettings => m_GlobalSettings; - internal static RenderGraph s_RenderGraph; - internal static RTHandleResourcePool s_RTHandlePool; + // All static variables for this class are cleaned up in Dispose(), which is always called when entering/exiting play mode. + // Therefore they are marked with [NoAutoStaticsCleanup] to mute analyzer warnings about them. + [NoAutoStaticsCleanup] internal static RenderGraph s_RenderGraph; + [NoAutoStaticsCleanup] internal static RTHandleResourcePool s_RTHandlePool; // Store locally the value on the instance due as the Render Pipeline Asset data might change before the disposal of the asset, making some APV Resources leak. internal bool apvIsEnabled = false; // Flag to check if offscreen UI cover prepass should be executed for the current frame. - internal static bool requireOffscreenUICoverPrepass; + [NoAutoStaticsCleanup] internal static bool requireOffscreenUICoverPrepass; // Flag to check if offscreen UI for HDR output is rendered in this frame at the first base camera. - internal static bool offscreenUIRenderedInCurrentFrame; + [NoAutoStaticsCleanup] internal static bool offscreenUIRenderedInCurrentFrame; // In some specific cases, we modify Screen.msaaSamples to reduce GPU bandwidth - internal static bool canOptimizeScreenMSAASamples { get; private set; } + [NoAutoStaticsCleanup] internal static bool canOptimizeScreenMSAASamples { get; private set; } // For iOS and macOS players, the Screen API MSAA samples change request is only applied in the next frame (UUM-42825) // To adress this, we need to store here the MSAA sample count at the beginning of the frame - internal static int startFrameScreenMSAASamples { get; private set; } + [NoAutoStaticsCleanup] internal static int startFrameScreenMSAASamples { get; private set; } // Reference to the asset associated with the pipeline. // When a pipeline asset is switched in `GraphicsSettings`, the `UniversalRenderPipelineCore.asset` member @@ -368,7 +376,7 @@ public UniversalRenderPipeline(UniversalRenderPipelineAsset asset) XRSystem.SetDisplayMSAASamples(msaaSamples); XRSystem.SetRenderScale(asset.renderScale); - Lightmapping.SetDelegate(lightsDelegate); + Lightmapping.SetDelegate(s_LightsDelegate); CameraCaptureBridge.enabled = true; @@ -465,6 +473,12 @@ protected override void Dispose(bool disposing) DisposeAdditionalCameraData(); AdditionalLightsShadowAtlasLayout.ClearStaticCaches(); + + CameraMetadataCache.Clear(); + requireOffscreenUICoverPrepass = false; + offscreenUIRenderedInCurrentFrame = false; + canOptimizeScreenMSAASamples = false; + startFrameScreenMSAASamples = 0; } // If the URP gets destroyed, we must clean up all the added URP specific camera data and @@ -1504,7 +1518,7 @@ static UniversalCameraData CreateCameraData(ContextContainer frameData, Camera c // Multiple cameras could render into the same XR display and they should share the same MSAA level. // However it should still respect the sample count of the target texture camera is rendering to. if (cameraData.xrRendering && rendererSupportsMSAA && camera.targetTexture == null) - msaaSamples = (int)XRSystem.GetDisplayMSAASamples(); + msaaSamples = (int)XRSystem.GetDisplayMSAASamples(); #if ENABLE_MULTI_WINDOWING && PLATFORM_SUPPORTS_PER_WINDOW_TRANSPARENCY && !UNITY_EDITOR bool needsAlphaChannel = GameWindowManager.IsGameWindowTransparent(cameraData.camera.targetDisplay); @@ -1617,7 +1631,7 @@ static void InitializeStackedCameraData(Camera baseCamera, UniversalAdditionalCa bool upscalerSupportsSharpening = activeUpscaler != null && activeUpscaler.supportsSharpening; #else // Convert the upscaling filter selection from the pipeline asset into an image upscaling filter - cameraData.upscalingFilter = supportedRenderingFeatures.upscaling? + cameraData.upscalingFilter = supportedRenderingFeatures.upscaling? ResolveUpscalingFilterSelection(new Vector2(cameraData.pixelWidth, cameraData.pixelHeight), cameraData.renderScale, settings.upscalingFilter) : ImageUpscalingFilter.Point; @@ -1686,7 +1700,7 @@ static void InitializeAdditionalCameraData(Camera camera, UniversalAdditionalCam using var profScope = new ProfilingScope(Profiling.Pipeline.initializeAdditionalCameraData); var renderer = GetRenderer(camera, additionalCameraData); - var settings = asset; + var settings = asset; bool anyShadowsEnabled = settings.supportsMainLightShadows || settings.supportsAdditionalLightShadows; cameraData.maxShadowDistance = Mathf.Min(settings.shadowDistance, camera.farClipPlane); @@ -1727,14 +1741,14 @@ static void InitializeAdditionalCameraData(Camera camera, UniversalAdditionalCam cameraData.screenSizeOverride = cameraData.pixelRect.size; cameraData.screenCoordScaleBias = Vector2.one; } - + var supportedRenderingFeatures = renderer.supportedRenderingFeatures; if (!supportedRenderingFeatures.cameraOpaqueTexture) cameraData.requiresOpaqueTexture = false; if (!supportedRenderingFeatures.cameraDepthTexture) - cameraData.requiresDepthTexture = false; + cameraData.requiresDepthTexture = false; cameraData.renderer = renderer; cameraData.postProcessingRequiresDepthTexture = CheckPostProcessForDepth(cameraData); @@ -1853,8 +1867,8 @@ static UniversalShadowData CreateShadowData(ContextContainer frameData, Universa UniversalCameraData cameraData = frameData.Get(); UniversalLightData lightData = frameData.Get(); - m_ShadowBiasData.Clear(); - m_ShadowResolutionData.Clear(); + s_ShadowBiasData.Clear(); + s_ShadowResolutionData.Clear(); shadowData.shadowmapDepthBufferBits = 16; shadowData.mainLightShadowCascadeBorder = urpAsset.cascadeBorder; @@ -1937,15 +1951,15 @@ static UniversalShadowData CreateShadowData(ContextContainer frameData, Universa { if (!shadowData.supportsMainLightShadows && i == mainLightIndex) { - m_ShadowBiasData.Add(Vector4.zero); - m_ShadowResolutionData.Add(0); + s_ShadowBiasData.Add(Vector4.zero); + s_ShadowResolutionData.Add(0); continue; } if (!shadowData.supportsAdditionalLightShadows && i != mainLightIndex) { - m_ShadowBiasData.Add(Vector4.zero); - m_ShadowResolutionData.Add(0); + s_ShadowBiasData.Add(Vector4.zero); + s_ShadowResolutionData.Add(0); continue; } @@ -1958,27 +1972,27 @@ static UniversalShadowData CreateShadowData(ContextContainer frameData, Universa } if (data && !data.usePipelineSettings) - m_ShadowBiasData.Add(new Vector4(light.shadowBias, light.shadowNormalBias, 0.0f, 0.0f)); + s_ShadowBiasData.Add(new Vector4(light.shadowBias, light.shadowNormalBias, 0.0f, 0.0f)); else - m_ShadowBiasData.Add(new Vector4(urpAsset.shadowDepthBias, urpAsset.shadowNormalBias, 0.0f, 0.0f)); + s_ShadowBiasData.Add(new Vector4(urpAsset.shadowDepthBias, urpAsset.shadowNormalBias, 0.0f, 0.0f)); if (data && (data.additionalLightsShadowResolutionTier == UniversalAdditionalLightData.AdditionalLightsShadowResolutionTierCustom)) { - m_ShadowResolutionData.Add((int)light.shadowResolution); // native code does not clamp light.shadowResolution between -1 and 3 + s_ShadowResolutionData.Add((int)light.shadowResolution); // native code does not clamp light.shadowResolution between -1 and 3 } else if (data && (data.additionalLightsShadowResolutionTier != UniversalAdditionalLightData.AdditionalLightsShadowResolutionTierCustom)) { int resolutionTier = Mathf.Clamp(data.additionalLightsShadowResolutionTier, UniversalAdditionalLightData.AdditionalLightsShadowResolutionTierLow, UniversalAdditionalLightData.AdditionalLightsShadowResolutionTierHigh); - m_ShadowResolutionData.Add(urpAsset.GetAdditionalLightsShadowResolution(resolutionTier)); + s_ShadowResolutionData.Add(urpAsset.GetAdditionalLightsShadowResolution(resolutionTier)); } else { - m_ShadowResolutionData.Add(urpAsset.GetAdditionalLightsShadowResolution(UniversalAdditionalLightData.AdditionalLightsShadowDefaultResolutionTier)); + s_ShadowResolutionData.Add(urpAsset.GetAdditionalLightsShadowResolution(UniversalAdditionalLightData.AdditionalLightsShadowDefaultResolutionTier)); } } - shadowData.bias = m_ShadowBiasData; - shadowData.resolution = m_ShadowResolutionData; + shadowData.bias = s_ShadowBiasData; + shadowData.resolution = s_ShadowResolutionData; shadowData.supportsSoftShadows = urpAsset.supportsSoftShadows && (shadowData.supportsMainLightShadows || shadowData.supportsAdditionalLightShadows); return shadowData; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs index 8cf4019f41c..2c3d947fff7 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs @@ -1034,6 +1034,7 @@ public static void InitializeShaderGlobalKeywords() // Keeping and calling this empty static function from pipeline creation ensures the static fields are // initialized at that point, instead of happening on the first frame, potentially causing a hitch. } + } /// @@ -1402,17 +1403,18 @@ public sealed partial class UniversalRenderPipeline { // Holds light direction for directional lights or position for punctual lights. // When w is set to 1.0, it means it's a punctual light. - static Vector4 k_DefaultLightPosition = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); - static Vector4 k_DefaultLightColor = Color.black; + static readonly Vector4 k_DefaultLightPosition = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); + static readonly Vector4 k_DefaultLightColor = Color.black; // Default light attenuation is setup in a particular way that it causes // directional lights to return 1.0 for both distance and angle attenuation - static Vector4 k_DefaultLightAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 1.0f); - static Vector4 k_DefaultLightSpotDirection = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); - static Vector4 k_DefaultLightsProbeChannel = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); + static readonly Vector4 k_DefaultLightAttenuation = new Vector4(0.0f, 1.0f, 0.0f, 1.0f); + static readonly Vector4 k_DefaultLightSpotDirection = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); + static readonly Vector4 k_DefaultLightsProbeChannel = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); - static List m_ShadowBiasData = new List(); - static List m_ShadowResolutionData = new List(); + // Note: No need to clear static lists on entering play mode as they are always cleared at the start of CreateShadowData() + static readonly List s_ShadowBiasData = new List(); + static readonly List s_ShadowResolutionData = new List(); /// /// Checks if a camera is a game camera. @@ -1555,7 +1557,7 @@ internal static RenderTextureDescriptor CreateRenderTextureDescriptor(Camera cam return desc; } - private static Lightmapping.RequestLightsDelegate lightsDelegate = (Light[] requests, NativeArray lightsOutput) => + private static readonly Lightmapping.RequestLightsDelegate s_LightsDelegate = (Light[] requests, NativeArray lightsOutput) => { LightDataGI lightData = new LightDataGI(); @@ -1902,17 +1904,18 @@ internal static void Initialize() #if ENABLE_VR && ENABLE_XR_MODULE #if PLATFORM_WINRT || PLATFORM_ANDROID // XR mobile platforms are not treated as dedicated mobile platforms in Core. Handle them specially here. (Quest and HL). - private static List displaySubsystemList = new List(); + // Note: No need to clear static list on entering playmode, because it is always overwritten by SubsystemManager.GetSubsystems before usage + private static readonly List s_DisplaySubsystemList = new List(); private static bool IsRunningXRMobile() { var platform = Application.platform; if (platform == RuntimePlatform.WSAPlayerX86 || platform == RuntimePlatform.WSAPlayerARM || platform == RuntimePlatform.WSAPlayerX64 || platform == RuntimePlatform.Android) { XR.XRDisplaySubsystem display = null; - SubsystemManager.GetSubsystems(displaySubsystemList); + SubsystemManager.GetSubsystems(s_DisplaySubsystemList); - if (displaySubsystemList.Count > 0) - display = displaySubsystemList[0]; + if (s_DisplaySubsystemList.Count > 0) + display = s_DisplaySubsystemList[0]; if (display != null) return true; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs index 6acfe8b073d..8777eb7a59f 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +using Unity.Scripting.LifecycleManagement; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.Universal.Internal; @@ -170,15 +171,15 @@ public sealed partial class UniversalRenderer // TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we should remove all RTHandles and use per frame RG textures. // We use 2 camera color handles so we can handle the edge case when a pass might want to read and write the same target. // This is not allowed so we just swap the current target, this keeps camera stacking working and avoids an extra blit pass. - private static RTHandle[] s_RenderGraphCameraColorHandles = new RTHandle[] - { - null, null - }; - private static RTHandle s_RenderGraphCameraDepthHandle; - private static int s_CurrentColorHandle = 0; - private static RTHandle s_RenderGraphDebugTextureHandle; - private static RTHandle s_OffscreenUIColorHandle; + // All static variables for this class are cleaned up in CleanupRenderGraphResources(), which is called when render pipeline + // is disposed (when entering/exiting play mode). Therefore they are marked with [NoAutoStaticsCleanup] to mute analyzer warnings about them. + [NoAutoStaticsCleanup] static readonly RTHandle[] s_RenderGraphCameraColorHandles = { null, null }; + [NoAutoStaticsCleanup] static RTHandle s_RenderGraphCameraDepthHandle; + [NoAutoStaticsCleanup] static int s_CurrentColorHandle = 0; + [NoAutoStaticsCleanup] static RTHandle s_RenderGraphDebugTextureHandle; + [NoAutoStaticsCleanup] static RTHandle s_OffscreenUIColorHandle; + [NoAutoStaticsCleanup] static bool s_RequiresIntermediateAttachments; private RTHandle currentRenderGraphCameraColorHandle { @@ -225,11 +226,19 @@ private RTHandle nextRenderGraphCameraColorHandle private void CleanupRenderGraphResources() { s_RenderGraphCameraColorHandles[0]?.Release(); + s_RenderGraphCameraColorHandles[0] = null; s_RenderGraphCameraColorHandles[1]?.Release(); + s_RenderGraphCameraColorHandles[1] = null; s_RenderGraphCameraDepthHandle?.Release(); + s_RenderGraphCameraDepthHandle = null; s_RenderGraphDebugTextureHandle?.Release(); + s_RenderGraphDebugTextureHandle = null; s_OffscreenUIColorHandle?.Release(); + s_OffscreenUIColorHandle = null; + + s_RequiresIntermediateAttachments = false; + s_CurrentColorHandle = 0; } /// @@ -727,8 +736,6 @@ public override bool supportsGPUOcclusion } } - private static bool s_RequiresIntermediateAttachments; - private void OnOffscreenDepthTextureRendering(RenderGraph renderGraph, ScriptableRenderContext context, UniversalResourceData resourceData, UniversalCameraData cameraData) { UniversalRenderingData renderingData = frameData.Get(); @@ -1961,7 +1968,7 @@ void DepthNormalPrepassRender(RenderGraph renderGraph, RenderPassInputSummary re static class RenderGraphUtils { - static private ProfilingSampler s_SetGlobalTextureProfilingSampler = new ProfilingSampler("Set Global Texture"); + static private readonly ProfilingSampler s_SetGlobalTextureProfilingSampler = new ProfilingSampler("Set Global Texture"); internal const int GBufferSize = 7; internal const int DBufferSize = 3; @@ -2005,7 +2012,7 @@ public static void SetGlobalTexture(RenderGraph graph, int nameId, TextureHandle } class ClearTargetsPass { - static private ProfilingSampler s_ClearProfilingSampler = new ProfilingSampler("Clear Targets"); + static private readonly ProfilingSampler s_ClearProfilingSampler = new ProfilingSampler("Clear Targets"); private class PassData { From f76abc1b9b99ef3e34b6f345587f5146ba47adb0 Mon Sep 17 00:00:00 2001 From: Paul Melamed Date: Thu, 23 Apr 2026 06:16:40 +0000 Subject: [PATCH 32/56] Shader optimizations/light indexing 16bitpacked --- .../ShaderLibrary/RealtimeLights.hlsl | 29 ++++++------------- .../ShaderLibrary/UnityInput.hlsl | 2 +- .../UniversalDOTSInstancing.hlsl | 2 +- .../BuiltIn/ShaderLibrary/Lighting.hlsl | 26 +++++++---------- .../BuiltIn/ShaderLibrary/UnityInput.hlsl | 2 +- 5 files changed, 22 insertions(+), 39 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl index ddf734664e3..312e2d257bc 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl @@ -195,6 +195,7 @@ uint GetPerObjectLightIndexOffset() // This abstract the underlying data implementation for storing lights/light indices int GetPerObjectLightIndex(uint index) { +#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA ///////////////////////////////////////////////////////////////////////////////////////////// // Structured Buffer Path / // / @@ -202,32 +203,20 @@ int GetPerObjectLightIndex(uint index) // Currently all non-mobile platforms take this path :( / // There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) / ///////////////////////////////////////////////////////////////////////////////////////////// -#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA uint offset = uint(unity_LightData.x); return _AdditionalLightsIndices[offset + index]; - +#else ///////////////////////////////////////////////////////////////////////////////////////////// // UBO path / // / -// We store 8 light indices in half4 unity_LightIndices[2]; / -// Due to memory alignment unity doesn't support int[] or float[] / -// Even trying to reinterpret cast the unity_LightIndices to float[] won't work / -// it will cast to float4[] and create extra register pressure. :( / +// We pack 8 x 16bit uint light indices into float4 unity_PackedLightIndices; / +// light index 0 is packed into lower 16 bits of unity_PackedLightIndices.x, / +// light index 1 is packed into high 16 bits of unity_PackedLightIndices.x and so on / ///////////////////////////////////////////////////////////////////////////////////////////// -#else - // since index is uint shader compiler will implement - // div & mod as bitfield ops (shift and mask). - - // TODO: Can we index a float4? Currently compiler is - // replacing unity_LightIndicesX[i] with a dp4 with identity matrix. - // u_xlat16_40 = dot(unity_LightIndices[int(u_xlatu13)], ImmCB_0_0_0[u_xlati1]); - // This increases both arithmetic and register pressure. - // - // NOTE: min16float4 bug workaround. - // Take the "vec4" part into float4 tmp variable in order to force float4 math. - // It appears indexing half4 as min16float4 on DX11 can fail. (dp4 {min16f}) - float4 tmp = unity_LightIndices[index / 4]; - return int(tmp[index % 4]); + uint4 packed4 = asuint(unity_PackedLightIndices); + uint2 pair = index >= 4 ? packed4.zw : packed4.xy; + uint word = (index & 2) ? pair.y : pair.x; + return (word >> ((index & 1) << 4)) & 0xFFFF; #endif } diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl index 4c17acbe804..9c5e8efd5bf 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl @@ -120,8 +120,8 @@ float4 unity_RenderingLayer; // Light Indices block feature // These are set internally by the engine upon request by RendererConfiguration. +float4 unity_PackedLightIndices; half4 unity_LightData; -half4 unity_LightIndices[2]; float4 unity_ProbesOcclusion; diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl index 69ab55f29c3..a75e2f5ad8b 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl @@ -48,7 +48,7 @@ UNITY_DOTS_INSTANCING_END(BuiltinPropertyMetadata) // Not supported by BatchRendererGroup. Just define them as constants. // ------------------------------------------------------------------------------ -static const float2x4 unity_LightIndices = float2x4(0,0,0,0, 0,0,0,0); +static const float4 unity_PackedLightIndices = float4(0,0,0,0); static const float4 unity_SpecCube0_BoxMax = float4(1,1,1,1); static const float4 unity_SpecCube0_BoxMin = float4(0,0,0,0); diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Lighting.hlsl b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Lighting.hlsl index 67926ca331f..70c67e466ce 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Lighting.hlsl +++ b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Lighting.hlsl @@ -202,6 +202,7 @@ int GetPerObjectLightIndex(uint index) { #ifndef BUILTIN_TARGET_API +#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA ///////////////////////////////////////////////////////////////////////////////////////////// // Structured Buffer Path / // / @@ -209,27 +210,20 @@ int GetPerObjectLightIndex(uint index) // Currently all non-mobile platforms take this path :( / // There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) / ///////////////////////////////////////////////////////////////////////////////////////////// -#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA - uint offset = unity_LightData.x; + uint offset = uint(unity_LightData.x); return _AdditionalLightsIndices[offset + index]; - +#else ///////////////////////////////////////////////////////////////////////////////////////////// // UBO path / // / -// We store 8 light indices in float4 unity_LightIndices[2]; / -// Due to memory alignment unity doesn't support int[] or float[] / -// Even trying to reinterpret cast the unity_LightIndices to float[] won't work / -// it will cast to float4[] and create extra register pressure. :( / +// We pack 8 x 16bit uint light indices into float4 unity_packedLightIndices; / +// light index 0 is packed into lower 16 bits of unity_packedLightIndices.x, / +// light index 1 is packed into high 16 bits of unity_packedLightIndices.x and so on / ///////////////////////////////////////////////////////////////////////////////////////////// -#else - // since index is uint shader compiler will implement - // div & mod as bitfield ops (shift and mask). - - // TODO: Can we index a float4? Currently compiler is - // replacing unity_LightIndicesX[i] with a dp4 with identity matrix. - // u_xlat16_40 = dot(unity_LightIndices[int(u_xlatu13)], ImmCB_0_0_0[u_xlati1]); - // This increases both arithmetic and register pressure. - return unity_LightIndices[index / 4][index % 4]; + uint4 packed4 = asuint(unity_PackedLightIndices); + uint2 pair = index >= 4 ? packed4.zw : packed4.xy; + uint word = (index & 2) ? pair.y : pair.x; + return (word >> ((index & 1) << 4)) & 0xFFFF; #endif #else return 0; diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/UnityInput.hlsl b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/UnityInput.hlsl index 03c6d48c4ac..ccb0647e8b6 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/UnityInput.hlsl +++ b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/UnityInput.hlsl @@ -107,8 +107,8 @@ real4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative // Light Indices block feature // These are set internally by the engine upon request by RendererConfiguration. +float4 unity_PackedLightIndices; real4 unity_LightData; -real4 unity_LightIndices[2]; float4 unity_ProbesOcclusion; From 22a12626249a474c3ec635ff6e07af16ebca47c6 Mon Sep 17 00:00:00 2001 From: Justinas Pliuskys Date: Thu, 23 Apr 2026 06:16:42 +0000 Subject: [PATCH 33/56] Scripting/deprecate forbidden api pt1 --- .../Editor/Data/Graphs/Vector1ShaderProperty.cs | 8 +++++++- .../Assets/CommonAssets/Editor/ShaderGraphParser.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs index e14af59d0d9..99fcc30bd6c 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1ShaderProperty.cs @@ -3,7 +3,9 @@ using System.Globalization; using UnityEditor.Graphing; using UnityEngine; - +#if UNITY_6000_5_OR_NEWER // LifeCycle API is available from here +using UnityEngine.Assemblies; +#endif namespace UnityEditor.ShaderGraph.Internal { [Serializable] @@ -173,7 +175,11 @@ internal static Type GetEnumHelper(string typeName) var type = Type.GetType(typeName, false, true); if (type != null) return type; +#if UNITY_6000_5_OR_NEWER // LifeCycle API is available from here + foreach (var a in CurrentAssemblies.GetLoadedAssemblies()) +#else foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) +#endif { type = a.GetType(typeName, false, true); if (type != null && type.IsEnum) diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/ShaderGraphParser.cs b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/ShaderGraphParser.cs index c22b2874543..b429477618d 100644 --- a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/ShaderGraphParser.cs +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/ShaderGraphParser.cs @@ -112,7 +112,7 @@ private static Dictionary CreateNodeDictionary() { // CORECLR_FIXME - Replace Assembly.LoadFile below with CurrentAssemblies.LoadFromPath once method is public (SCP-1544) // Non-asmdef way - Assembly sga = Assembly.LoadFile(UnityEngine.Application.dataPath + "/../Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll"); + Assembly sga = CurrentAssemblies.LoadFromPath(UnityEngine.Application.dataPath + "/../Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll"); Type abstractMatNode = sga.GetType("UnityEditor.ShaderGraph.AbstractMaterialNode"); Type masterNodeType = sga.GetType("UnityEditor.ShaderGraph.IMasterNode"); List types = sga.GetTypes() From 750aaa80c1628c53ace1c0ae2a17493dd29bd6c6 Mon Sep 17 00:00:00 2001 From: Sebastien Phaneuf Date: Thu, 23 Apr 2026 06:16:52 +0000 Subject: [PATCH 34/56] Use IMGUI drawer to bypass ui issue with Light Rendering Layer --- .../Editor/Lighting/HDLightingSearchColumnProviders.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs index 1d8fe4e7b39..0d74ae14cd2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchColumnProviders.cs @@ -14,6 +14,7 @@ static class HDLightingSearchColumnProviders internal const string k_LightShapePath = k_LightPath + "ShapeHDRP"; internal const string k_LightIntensityPath = k_LightPath + "Intensity"; internal const string k_LightIntensityUnitPath = k_LightPath + "IntensityUnit"; + internal const string k_LightLayerPath = k_LightPath + "LightLayer"; internal const string k_LightModePath = k_LightPath + "ModeHDRP"; internal const string k_ContactShadowsPath = k_LightPath + "ContactShadows"; internal const string k_ShadowResolutionPath = k_LightPath + "ShadowResolution"; @@ -231,6 +232,7 @@ public static void RayTracingModeSearchColumnProvider(SearchColumn column) }; } + [SearchColumnProvider(k_ReflectionProbeResolutionPath)] public static void ReflectionProbeResolutionSearchColumnProvider(SearchColumn column) { From 0330cb5d26f091228efd83d78c0318a9072929eb Mon Sep 17 00:00:00 2001 From: Pema Malling Date: Thu, 23 Apr 2026 06:16:54 +0000 Subject: [PATCH 35/56] Fix SSR depth refinement failing on Android phone due to driver bug. --- .../ShaderLibrary/ComputeScreenSpaceReflection.hlsl | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl index a1b77574043..bce3a1620b9 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ComputeScreenSpaceReflection.hlsl @@ -176,6 +176,7 @@ bool TraceScreenSpaceRay( bool aboveBase = !COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepth); bool belowFloor = COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepth * GetThicknessScale() + GetThicknessBias()); + [branch] if (aboveBase && belowFloor) { hitFine = COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepth * GetThicknessScaleFine() + GetThicknessBiasFine()); From 1f8461415fa46047e1f0c655f8102770d5a6bd93 Mon Sep 17 00:00:00 2001 From: Roland Kindermann Date: Thu, 23 Apr 2026 07:53:13 +0000 Subject: [PATCH 36/56] Fix Rendering Debugger going blank when search yields no results --- .../Editor/Debugging/DebugWindow.SearchFilter.cs | 5 +++++ .../Editor/Debugging/DebugWindow.uss | 5 +++++ .../Editor/Debugging/DebugWindow.uxml | 1 + 3 files changed, 11 insertions(+) diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs index 598e6490a18..84b48fb80e7 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs @@ -29,11 +29,13 @@ sealed partial class DebugWindow readonly Dictionary m_WidgetSearchElementCache = new(); readonly List m_PanelHeaderTextElements = new(); UIElementSearchFilter m_SearchFilter; + Label m_NoResultsLabel; void BuildSearchCache() { m_WidgetSearchElementCache.Clear(); m_PanelHeaderTextElements.Clear(); + m_NoResultsLabel = rootVisualElement.Q /// The index of the current frame, used to cycle through jitter patterns. + /// The ratio of output resolution to input resolution (e.g., 2.0 for 1080p → 4K). /// Outputs the calculated sub-pixel jitter vector. /// Outputs whether the jitter vector permits scaling relative to resolution. - void CalculateJitter(int frameIndex, out Vector2 jitter, out bool allowScaling); + void CalculateJitter(int frameIndex, float upscaleRatio, out Vector2 jitter, out bool allowScaling); /// /// Determines the render resolution based on display resolution and optional internal upscaler state or options. @@ -52,6 +53,15 @@ public interface IUpscaler : IRenderGraphRecorder /// The rendering resolution prior to upscaling. This is passed by reference and can be modified. /// The target display or output resolution. void NegotiatePreUpscaleResolution(ref Vector2Int preUpscaleResolution, Vector2Int postUpscaleResolution); + + /// + /// Creates a new context for this upscaler. Upscaler authors implement this to create per-camera state. + /// Called by the context manager when a new camera needs upscaling or when an existing context is invalidated. + /// + /// The upscaler options to create the context with. + /// The target display resolution. + /// A new context instance, or null for spatial upscalers that don't need context. + IUpscalerContext CreateContext(UpscalerOptions options, Vector2Int displayResolution); #endregion } @@ -79,8 +89,11 @@ public abstract class AbstractUpscaler : IUpscaler /// public virtual void NegotiatePreUpscaleResolution(ref Vector2Int preUpscaleResolution, Vector2Int postUpscaleResolution) {} - /// - public virtual void CalculateJitter(int frameIndex, out Vector2 jitter, out bool allowScaling) + /// + public virtual IUpscalerContext CreateContext(UpscalerOptions options, Vector2Int displayResolution) => null; + + /// + public virtual void CalculateJitter(int frameIndex, float upscaleRatio, out Vector2 jitter, out bool allowScaling) { jitter = -STP.Jit16(frameIndex); allowScaling = false; @@ -90,6 +103,112 @@ public virtual void CalculateJitter(int frameIndex, out Vector2 jitter, out bool public virtual void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { } } + /// + /// Represents a per-camera context for temporal upscalers. + /// Each camera (and XR view) gets its own context to maintain separate temporal history. + /// Spatial upscalers that don't need history can return null from CreateContext(). + /// + public interface IUpscalerContext + { + /// + /// The display resolution this context was created for. Upscaler authors set this at creation time. + /// The context manager reads it to detect resolution and options changes that require context recreation. + /// + Vector2Int createdForDisplayResolution { get; } + + /// + /// The frame number when this context was last used. + /// Set automatically by the context manager each frame to track when unused contexts should be cleaned up. + /// + int lastUsedFrame { get; set; } + + /// + /// Checks if this context is still valid for the given options. Upscaler authors implement the validation logic. + /// The context manager calls this each frame to determine if the context needs recreation. + /// + /// The current upscaler options to validate against. + /// True if the context is still valid, false if it needs to be recreated. + bool IsValidForOptions(UpscalerOptions options); + + /// + /// Releases native resources associated with this context. Upscaler authors implement this to release GPU resources + /// when plugins or native code require command buffer access for cleanup. + /// Called automatically by the context manager when the context expires or needs recreation. + /// + /// The command buffer to record cleanup commands into. + void Cleanup(CommandBuffer cmd); + } + + /// + /// Base class for plugin-based upscaler contexts (DLSS, FSR, XeSS, etc.). + /// Handles common patterns: resolution tracking, type-safe validation, and cleanup. + /// Plugin upscalers extend this class and implement the abstract methods. + /// + /// The native context type from the plugin (e.g., DLSSContext, FSR2Context). + /// The options type for this upscaler (e.g., DLSSOptions, FSR2Options). + public abstract class PluginUpscalerContext : IUpscalerContext + where TNativeContext : class + where TOptions : UpscalerOptions + { + /// + /// The native context from the plugin. Subclasses create this via GetOrCreateNativeContext(). + /// + protected TNativeContext m_NativeContext; + + /// + public Vector2Int createdForDisplayResolution { get; } + + /// + public int lastUsedFrame { get; set; } + + /// + /// Returns true if the native context has been created. + /// Use this to skip building initialization settings when the context already exists. + /// + public bool hasNativeContext => m_NativeContext != null; + + /// + /// Creates a new plugin upscaler context for the specified display resolution. + /// + /// The target display resolution. + protected PluginUpscalerContext(Vector2Int displayResolution) + { + createdForDisplayResolution = displayResolution; + } + + /// + /// Destroys the native context using the plugin API. + /// Called by the base class Cleanup() method. + /// + /// The command buffer to record destruction commands into. + /// The native context to destroy. + protected abstract void DestroyNativeContext(CommandBuffer cmd, TNativeContext context); + + /// + /// Validates whether the current options match the options this context was created with. + /// Subclasses compare tracked option values against the provided options. + /// + /// The current options to validate against. + /// True if the context is still valid for these options. + protected abstract bool ValidateOptions(TOptions options); + + /// + public bool IsValidForOptions(UpscalerOptions options) + { + return options is TOptions typed && ValidateOptions(typed); + } + + /// + public void Cleanup(CommandBuffer cmd) + { + if (m_NativeContext != null) + { + DestroyNativeContext(cmd, m_NativeContext); + m_NativeContext = null; + } + } + } + /// /// Defines the inputs and outputs required for an upscaling pass. /// @@ -132,6 +251,9 @@ public enum MotionVectorDirection #endregion #region BACKING_FIELDS + // Context + private IUpscalerContext m_Context; + // Texture I/O private TextureHandle m_CameraColor; private TextureHandle m_CameraDepth; @@ -157,7 +279,6 @@ public enum MotionVectorDirection private float m_FarClipPlane; private float m_FieldOfViewDegrees; private int m_NumActiveViews; - private int m_EyeIndex; private Vector3[] m_WorldSpaceCameraPositions; private Vector3[] m_PreviousWorldSpaceCameraPositions; private Vector3[] m_PreviousPreviousWorldSpaceCameraPositions; @@ -382,15 +503,6 @@ public int numActiveViews set { m_NumActiveViews = value; } } - /// - /// The index of the current eye being rendered (for XR). - /// - public int eyeIndex - { - get { return m_EyeIndex; } - set { m_EyeIndex = value; } - } - /// /// The camera positions in world space for the current frame. /// @@ -553,10 +665,39 @@ public bool enableHwDrs } #endregion + #region CONTEXT + /// + /// The per-camera context for the active upscaler. + /// Populated by the pipeline before calling RecordRenderGraph(). + /// Temporal upscalers read this to access their history buffers. + /// Spatial upscalers that don't need context will have this set to null. + /// + public IUpscalerContext context + { + get { return m_Context; } + set { m_Context = value; } + } + + /// + /// The sub-pixel jitter offset applied to the projection matrix this frame. + /// Populated by the pipeline after calling IUpscaler.CalculateJitter(). + /// Values are typically in the range [-0.5, 0.5]. + /// Temporal upscalers pass this to their native APIs to inform them of the jitter applied. + /// + public Vector2 subpixelJitter + { + get { return m_SubpixelJitter; } + set { m_SubpixelJitter = value; } + } + private Vector2 m_SubpixelJitter; + #endregion + /// public override void Reset() { + context = null; + subpixelJitter = Vector2.zero; cameraColor = TextureHandle.nullHandle; cameraDepth = TextureHandle.nullHandle; motionVectorColor = TextureHandle.nullHandle; @@ -580,7 +721,6 @@ public override void Reset() farClipPlane = 0f; fieldOfViewDegrees = 0f; numActiveViews = 0; - eyeIndex = 0; worldSpaceCameraPositions = Array.Empty(); previousWorldSpaceCameraPositions = Array.Empty(); previousPreviousWorldSpaceCameraPositions = Array.Empty(); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/Upscaling.cs b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/Upscaling.cs index d4cd069b5c7..a09d5e1a9f5 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/Upscaling.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/Upscaling.cs @@ -5,6 +5,156 @@ namespace UnityEngine.Rendering { + /// + /// Manages per-camera upscaler contexts. Handles context creation, caching, validation, and expiry. + /// + internal class UpscalerContextManager + { + private struct ContextKey : IEquatable + { + public ulong cameraId; + public string upscalerName; + + public ContextKey(ulong cameraId, string upscalerName) + { + this.cameraId = cameraId; + this.upscalerName = upscalerName; + } + + public bool Equals(ContextKey other) + { + return cameraId == other.cameraId && + upscalerName == other.upscalerName; + } + + public override bool Equals(object? obj) => obj is ContextKey other && Equals(other); + public override int GetHashCode() => HashCode.Combine(cameraId, upscalerName); + } + + // Contexts unused for this many frames are automatically cleaned up. + // 400 frames at 60 FPS ≈ 6.7 seconds. This threshold follows the pattern + // established in HDRP's existing context management. + private const int k_ContextExpiryFrames = 400; + private readonly Dictionary m_Contexts = new(); + private readonly List m_KeysToRemove = new(); // Reusable list for cleanup + private readonly List m_InvalidatedContexts = new(); // Contexts pending cleanup + + /// + /// Acquires a context for the specified camera and upscaler. + /// Returns a cached context if valid, or creates a new one if missing or invalid. + /// Also updates the context's last-used frame for expiry tracking. + /// + /// Unique ID for the camera. In XR scenarios, this must be unique per view (encode eye information into the ID). + /// The upscaler to acquire a context for. + /// The current upscaler options. + /// The target display resolution. + /// The context, or null for spatial upscalers that don't need context. + public IUpscalerContext? AcquireContext( + ulong cameraId, + IUpscaler upscaler, + UpscalerOptions options, + Vector2Int displayResolution) + { + var key = new ContextKey(cameraId, upscaler.name); + + // Note: Time.frameCount may not advance in Editor when Game view is inactive. + // This is acceptable because contexts are only acquired during active rendering, + // and lastUsedFrame is updated on every AcquireContext call. If a more robust + // solution is needed (e.g., for scene view upscaling), consider using + // Time.realtimeSinceStartup or a pipeline-provided render counter. + int currentFrame = Time.frameCount; + + if (m_Contexts.TryGetValue(key, out var existingContext)) + { + // Check if context is still valid + bool resolutionValid = existingContext.createdForDisplayResolution == displayResolution; + bool optionsValid = existingContext.IsValidForOptions(options); + + if (resolutionValid && optionsValid) + { + existingContext.lastUsedFrame = currentFrame; + return existingContext; + } + + // Context is invalid, queue it for cleanup and remove from cache + m_InvalidatedContexts.Add(existingContext); + m_Contexts.Remove(key); + } + + // Create new context + var newContext = upscaler.CreateContext(options, displayResolution); + if (newContext != null) + { + newContext.lastUsedFrame = currentFrame; + m_Contexts[key] = newContext; + } + else if (upscaler.isTemporal) + { + // Temporal upscalers should always return a context. Null indicates + // a creation failure (e.g., plugin not loaded, GPU not supported). + Debug.LogWarning($"[UpscalerContextManager] Temporal upscaler '{upscaler.name}' returned null context. " + + "Upscaling may not function correctly."); + } + + return newContext; + } + + /// + /// Removes contexts that haven't been used for more than k_ContextExpiryFrames frames. + /// Also cleans up any contexts that were invalidated (due to resolution or option changes). + /// Should be called once per frame from the render pipeline. + /// + public void CleanupExpiredContexts(CommandBuffer cmd) + { + // Clean up invalidated contexts first + foreach (var context in m_InvalidatedContexts) + { + context.Cleanup(cmd); + } + m_InvalidatedContexts.Clear(); + + // Clean up expired contexts (see AcquireContext for Time.frameCount limitations) + int currentFrame = Time.frameCount; + m_KeysToRemove.Clear(); + + foreach (var kvp in m_Contexts) + { + var context = kvp.Value; + int framesSinceLastUse = currentFrame - context.lastUsedFrame; + if (framesSinceLastUse > k_ContextExpiryFrames) + { + context.Cleanup(cmd); + m_KeysToRemove.Add(kvp.Key); + } + } + + foreach (var key in m_KeysToRemove) + { + m_Contexts.Remove(key); + } + } + + /// + /// Cleans up all contexts. Called when the upscaling system is disposed. + /// + public void Dispose(CommandBuffer cmd) + { + // Clean up any pending invalidated contexts + foreach (var context in m_InvalidatedContexts) + { + context.Cleanup(cmd); + } + m_InvalidatedContexts.Clear(); + + // Clean up all active contexts + foreach (var kvp in m_Contexts) + { + kvp.Value.Cleanup(cmd); + } + m_Contexts.Clear(); + } + } + public static class UpscalerRegistry { public static readonly Dictionary s_RegisteredUpscalers = new(); @@ -55,6 +205,7 @@ public UpscalerEntry(IUpscaler instance, UpscalerIntegrationType integrationType private List m_Upscalers = new List(); private string[] m_UpscalerNamesCache; private int m_ActiveUpscalerIndex = -1; + private readonly UpscalerContextManager m_ContextManager = new(); #endregion /// @@ -204,6 +355,39 @@ public int IndexOf(string upscalerName) Debug.LogErrorFormat($"Upscaler type {T} not found"); return null; } + + #region Context Management + + /// + /// Acquires an upscaler context for the specified camera. + /// Returns a cached context if valid, or creates a new one if missing or invalid. + /// Also updates the context's last-used frame for expiry tracking. + /// + /// Unique ID for the camera. In XR scenarios, this must be unique per view (encode eye information into the ID). + /// The upscaler to acquire a context for. + /// The current upscaler options. + /// The target display resolution. + /// The context, or null for spatial upscalers that don't need context. + public IUpscalerContext? AcquireContext( + ulong cameraId, + IUpscaler upscaler, + UpscalerOptions options, + Vector2Int displayResolution) + { + return m_ContextManager.AcquireContext(cameraId, upscaler, options, displayResolution); + } + + /// + /// Cleans up contexts that haven't been used for a while (400 frames). + /// Should be called once per frame from the render pipeline. + /// + /// The command buffer to record cleanup commands into. + public void CleanupExpiredContexts(CommandBuffer cmd) + { + m_ContextManager.CleanupExpiredContexts(cmd); + } + + #endregion } } #endif 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 13774a78bec..8c668443432 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 @@ -2381,7 +2381,11 @@ internal Matrix4x4 GetJitteredProjectionMatrix(Matrix4x4 origProj) Debug.Assert(HDRenderPipeline.currentPipeline != null); IUpscaler upscaler = HDRenderPipeline.currentPipeline.upscaling.activeUpscaler; Debug.Assert(upscaler != null); // If we're in this condition, upscaler should be non-null. - upscaler.CalculateJitter(taaFrameIndex, out Vector2 jitter, out bool allowScaling); + + // Compute upscale ratio for upscalers that need resolution-dependent jitter (DLSS, FSR2) + float upscaleRatio = finalViewport.width / actualWidth; + upscaler.CalculateJitter(taaFrameIndex, upscaleRatio, out Vector2 jitter, out bool allowScaling); + // TODO (Apoorva): Re-examine if this negative sign is needed. It's currently there because URP and HDRP // seem to be different in this regard. In URP, the jitter offset is -STP.Jit16(), while in HDRP, it // seems to be STP.Jit16(). Maybe the usage of the jitter vector cancels this sign out, making the math diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index 145ed426cd9..4b8c94f62b5 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs @@ -1089,7 +1089,6 @@ TextureHandle inputStencil Debug.Assert(numActiveViews <= STP.perViewConfigs.Length); io.numActiveViews = numActiveViews; - io.eyeIndex = 0; // Maybe we should rename this to viewIndexBias or maybe even find a way to remove this entirely. io.worldSpaceCameraPositions = new Vector3[numActiveViews]; io.previousWorldSpaceCameraPositions = new Vector3[numActiveViews]; io.previousPreviousWorldSpaceCameraPositions = new Vector3[numActiveViews]; @@ -1148,6 +1147,19 @@ TextureHandle inputStencil // Insert the active upscaler's render graph passes IUpscaler upscaler = upscaling.activeUpscaler; Debug.Assert(upscaler != null); + + // Acquire the per-camera context for the active upscaler + // HDRP already has separate HDCamera instances per eye in multi-pass XR, so cameraInstanceID is already unique per view + io.context = upscaling.AcquireContext( + io.cameraInstanceID, + upscaler, + upscaler.options, + io.postUpscaleResolution + ); + + // Use jitter already computed during camera setup (stored in taaJitter with correct sign) + io.subpixelJitter = new Vector2(hdCamera.taaJitter.x, hdCamera.taaJitter.y); + upscaler.RecordRenderGraph(renderGraph, hdCamera.contextContainer); return io.cameraColor; 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 944db9dfcda..9ca1359530c 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 @@ -2526,6 +2526,17 @@ protected override void Render(ScriptableRenderContext renderContext, List 400 frames) + if (upscaling != null) + { + var cmd = CommandBufferPool.Get("Upscaler Context Cleanup"); + upscaling.CleanupExpiredContexts(cmd); + renderContext.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + } +#endif + EndContextRendering(renderContext, cameras); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs index dd10be4aa33..026222ad6ba 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs @@ -599,6 +599,10 @@ internal bool IsSTPEnabled() // TAA settings. internal TemporalAA.Settings taaSettings; + // Sub-pixel jitter applied to the projection matrix this frame. + // Computed once during camera setup, read by upscalers during post-process. + internal Vector2 subpixelJitter; + // Post-process history reset has been triggered for this camera. internal bool resetHistory { @@ -676,6 +680,7 @@ public override void Reset() taaHistory = null; stpHistory = null; taaSettings = default; + subpixelJitter = default; baseCamera = null; isLastBaseCamera = false; stackAnyPostProcessingEnabled = false; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs index 22ef5d258b8..3d7879ef220 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcess/UpscalerPostProcessPass.cs @@ -79,7 +79,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer io.flippedX = false; io.hdrInput = Experimental.Rendering.GraphicsFormatUtility.IsHDRFormat(srcDesc.format); io.numActiveViews = cameraData.xr.enabled ? cameraData.xr.viewCount : 1; - io.eyeIndex = (cameraData.xr.enabled && !cameraData.xr.singlePassEnabled) ? cameraData.xr.multipassId : 0; io.worldSpaceCameraPositions = new Vector3[io.numActiveViews]; io.previousWorldSpaceCameraPositions = new Vector3[io.numActiveViews]; io.previousPreviousWorldSpaceCameraPositions = new Vector3[io.numActiveViews]; @@ -96,10 +95,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer io.previousViewMatrices = motionData.previousViewStereo; io.previousPreviousViewMatrices = motionData.previousPreviousViewStereo; io.resetHistory = cameraData.resetHistory; - // TODO (Apoorva): Maybe we want to support this? - // URP supports adding an offset value to the TAA frame index for testing determinism as follows: - // io.frameIndex = Time.frameCount + settings.jitterFrameCountOffset; - io.frameIndex = Time.frameCount; + io.frameIndex = TemporalAA.CalculateTaaFrameIndex(ref cameraData.taaSettings); io.deltaTime = motionData.deltaTime; io.previousDeltaTime = motionData.lastDeltaTime; io.blueNoiseTextureSet = m_BlueNoise16LTex; @@ -113,8 +109,26 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer io.enableMotionScaling = true; #endif io.enableHwDrs = false; // URP doesn't support hardware dynamic resolution scaling + + // Acquire the per-camera context for the active upscaler + // In XR multi-pass rendering, encode eye information into the camera ID to ensure separate contexts per eye + var upscaler = postProcessingData.activeUpscaler; + ulong viewId = io.cameraInstanceID; + if (cameraData.xr.enabled && !cameraData.xr.singlePassEnabled) + viewId = (ulong)HashCode.Combine(io.cameraInstanceID, cameraData.xr.multipassId); + + io.context = UniversalRenderPipeline.upscaling.AcquireContext( + viewId, + upscaler, + upscaler.options, + io.postUpscaleResolution + ); + + // Use jitter already computed during camera setup + io.subpixelJitter = cameraData.subpixelJitter; + // Insert the active upscaler's render graph passes - postProcessingData.activeUpscaler.RecordRenderGraph(renderGraph, frameData); + upscaler.RecordRenderGraph(renderGraph, frameData); // Update the camera resolution to reflect the upscaled size var dstDesc = io.cameraColor.GetDescriptor(renderGraph); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs b/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs index b091b28106d..fc7a1dbcbbe 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs @@ -199,31 +199,35 @@ internal static int CalculateTaaFrameIndex(ref Settings settings) internal static Matrix4x4 CalculateJitterMatrix(UniversalCameraData cameraData, JitterFunc jitterFunc) { - Matrix4x4 jitterMat = Matrix4x4.identity; + if (!cameraData.IsTemporalAAEnabled()) + return Matrix4x4.identity; - bool isJitter = cameraData.IsTemporalAAEnabled(); - if (isJitter) - { - int taaFrameIndex = CalculateTaaFrameIndex(ref cameraData.taaSettings); + int taaFrameIndex = CalculateTaaFrameIndex(ref cameraData.taaSettings); + float jitterScale = cameraData.taaSettings.jitterScale; - float actualWidth = cameraData.cameraTargetDescriptor.width; - float actualHeight = cameraData.cameraTargetDescriptor.height; - float jitterScale = cameraData.taaSettings.jitterScale; + jitterFunc(taaFrameIndex, out Vector2 jitter, out bool allowScaling); - Vector2 jitter; - bool allowScaling; - jitterFunc(taaFrameIndex, out jitter, out allowScaling); + if (allowScaling) + jitter *= jitterScale; - if (allowScaling) - jitter *= jitterScale; + return CalculateJitterMatrix(cameraData, jitter); + } - float offsetX = jitter.x * (2.0f / actualWidth); - float offsetY = jitter.y * (2.0f / actualHeight); + /// + /// Builds a jitter matrix from a pre-computed sub-pixel jitter offset. + /// Used by upscalers that compute jitter with resolution-dependent parameters. + /// + /// Camera data containing render target dimensions. + /// Sub-pixel jitter offset, typically in range [-0.5, 0.5]. + internal static Matrix4x4 CalculateJitterMatrix(UniversalCameraData cameraData, Vector2 subpixelJitter) + { + float actualWidth = cameraData.cameraTargetDescriptor.width; + float actualHeight = cameraData.cameraTargetDescriptor.height; - jitterMat = Matrix4x4.Translate(new Vector3(offsetX, offsetY, 0.0f)); - } + float offsetX = subpixelJitter.x * (2.0f / actualWidth); + float offsetY = subpixelJitter.y * (2.0f / actualHeight); - return jitterMat; + return Matrix4x4.Translate(new Vector3(offsetX, offsetY, 0.0f)); } internal static void CalculateJitter(int frameIndex, out Vector2 jitter, out bool allowScaling) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index d19fcb71e9a..b048661a788 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -628,6 +628,17 @@ protected override void Render(ScriptableRenderContext renderContext, List 400 frames) + if (upscaling != null) + { + var cmd = CommandBufferPool.Get("Upscaler Context Cleanup"); + upscaling.CleanupExpiredContexts(cmd); + renderContext.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + } +#endif } #if ENABLE_SHADER_DEBUG_PRINT @@ -1792,25 +1803,38 @@ static void InitializeAdditionalCameraData(Camera camera, UniversalAdditionalCam // Affects the jitter set just below. Do not move. ApplyTaaRenderingDebugOverrides(ref cameraData.taaSettings); - TemporalAA.JitterFunc jitterFunc; + Matrix4x4 jitterMat = Matrix4x4.identity; // Depends on the cameraTargetDesc, size and MSAA also XR modifications of those. #if ENABLE_UPSCALER_FRAMEWORK IUpscaler activeUpscaler = upscaling.activeUpscaler; if (cameraData.IsTemporalAAEnabled() && activeUpscaler != null) { - jitterFunc = activeUpscaler.CalculateJitter; + // Upscalers compute jitter with resolution-dependent parameters. + int taaFrameIndex = TemporalAA.CalculateTaaFrameIndex(ref cameraData.taaSettings); + float actualWidth = cameraData.cameraTargetDescriptor.width; + float upscaleRatio = (float)cameraData.pixelWidth / actualWidth; + + activeUpscaler.CalculateJitter(taaFrameIndex, upscaleRatio, out Vector2 subpixelJitter, out bool allowScaling); + + // Note: DLSS/FSR2 set allowScaling=false, so jitterScale is not applied + if (allowScaling) + subpixelJitter *= cameraData.taaSettings.jitterScale; + + // Store for later use by upscaler during post-process + cameraData.subpixelJitter = subpixelJitter; + + jitterMat = TemporalAA.CalculateJitterMatrix(cameraData, subpixelJitter); } else #endif if (cameraData.IsSTPEnabled()) { - jitterFunc = StpUtils.s_JitterFunc; + jitterMat = TemporalAA.CalculateJitterMatrix(cameraData, StpUtils.s_JitterFunc); } else { - jitterFunc = TemporalAA.s_JitterFunc; + jitterMat = TemporalAA.CalculateJitterMatrix(cameraData, TemporalAA.s_JitterFunc); } - Matrix4x4 jitterMat = TemporalAA.CalculateJitterMatrix(cameraData, jitterFunc); cameraData.SetViewProjectionAndJitterMatrix(camera.worldToCameraMatrix, projectionMatrix, jitterMat); cameraData.worldSpaceCameraPos = camera.transform.position; From d4a9a453495d8de56053e1c550cc0688b7b878b6 Mon Sep 17 00:00:00 2001 From: Kenny Tan Date: Thu, 23 Apr 2026 14:31:34 +0000 Subject: [PATCH 40/56] [UUM-134522][UUM-136056][URP 2D][6000.6] Fix 2d shadow volumetric bugs --- .../Runtime/2D/Lights/Light2DCullResult.cs | 2 +- .../Runtime/2D/Passes/Utility/RendererLighting.cs | 5 +++++ .../Runtime/2D/Rendergraph/DrawLight2DPass.cs | 3 ++- .../Runtime/2D/Rendergraph/DrawShadow2DPass.cs | 5 +++++ .../Runtime/2D/Rendergraph/Renderer2DRendergraph.cs | 10 +++++++++- .../Shaders/2D/Include/LightingUtility.hlsl | 4 ++-- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DCullResult.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DCullResult.cs index 7ced864a6bf..c5cb4033581 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DCullResult.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Lights/Light2DCullResult.cs @@ -74,7 +74,7 @@ public LightStats GetLightStatsByLayer(int layerID, ref LayerBatch layer) returnStats.totalNormalMapUsage++; if (light.volumeIntensity > 0 && light.volumetricEnabled) returnStats.totalVolumetricUsage++; - if (light.volumeIntensity > 0 && light.volumetricEnabled && RendererLighting.CanCastShadows(light, layerID)) + if (RendererLighting.CanCastVolumetricShadows(light, layer.endLayerValue)) returnStats.totalVolumetricShadowUsage++; returnStats.blendStylesUsed |= (uint)(1 << light.blendStyleIndex); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs index b62602ca66b..bb4d4ed924e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/RendererLighting.cs @@ -153,6 +153,11 @@ internal static bool CanCastShadows(Light2D light, int layerToRender) return light.shadowsEnabled && light.shadowIntensity > 0 && light.IsLitLayer(layerToRender); } + internal static bool CanCastVolumetricShadows(Light2D light, int endLayerValue) + { + return light.volumeIntensity > 0 && light.volumetricEnabled && light.renderVolumetricShadows && light.GetTopMostLitLayer() == endLayerValue; + } + internal static void SetLightShaderGlobals(IRasterCommandBuffer cmd, Light2DBlendStyle[] lightBlendStyles, int[] blendStyleIndices) { for (var i = 0; i < blendStyleIndices.Length; i++) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs index a5add8656b9..32e461c06f7 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs @@ -86,7 +86,8 @@ private static void Execute(RasterCommandBuffer cmd, PassData passData, LayerBat layerBatch.endLayerValue != light.GetTopMostLitLayer())) continue; - var useShadows = passData.layerBatch.lightStats.useShadows && layerBatch.shadowIndices.Contains(j); + var useShadows = (!passData.isVolumetric && passData.layerBatch.lightStats.useShadows) || (passData.isVolumetric && passData.layerBatch.lightStats.useVolumetricShadowLights); + useShadows &= layerBatch.shadowIndices.Contains(j); var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric, useShadows); var lightMesh = light.lightMesh; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs index 6fc8ded1de0..1a8b0f66e7c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs @@ -33,6 +33,7 @@ internal class PassData internal Renderer2DData rendererData; internal TextureHandle[] shadowTextures; internal TextureHandle shadowDepth; + internal bool isVolumetric; } public void Render(RenderGraph graph, ContextContainer frameData, int batchIndex, bool isVolumetric = false) @@ -52,6 +53,7 @@ public void Render(RenderGraph graph, ContextContainer frameData, int batchIndex using (var builder = graph.AddUnsafePass(passName, out var passData, LayerDebug.GetProfilingSampler(passName, profilingSampler))) { + passData.isVolumetric = isVolumetric; passData.layerBatch = layerBatch; passData.rendererData = rendererData; passData.shadowTextures = universal2DResourceData.shadowTextures[batchIndex]; @@ -72,6 +74,9 @@ public void Render(RenderGraph graph, ContextContainer frameData, int batchIndex var index = data.layerBatch.shadowIndices[i]; var light = data.layerBatch.lights[index]; + if (data.isVolumetric && !RendererLighting.CanCastVolumetricShadows(light, data.layerBatch.endLayerValue)) + continue; + // Shadow Pass ExecuteShadowPass(cmd, data, light, i); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs index 81990b91d56..e37221e072e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs @@ -207,6 +207,13 @@ private RenderPassInputSummary GetRenderPassInputs() inputSummary.requiresColorTexture |= needsColor; } + // Volumetric shadow pass requires intermediate texture + bool hasVolumetricShadowPass = false; + var layerBatches = frameData.Get().layerBatches; + var batchCount = frameData.Get().batchCount; + for (int i = 0; i < batchCount; ++i) + hasVolumetricShadowPass |= layerBatches[i].lightStats.useVolumetricShadowLights; + inputSummary.requiresColorTexture |= cameraData.postProcessEnabled || cameraData.isHdrEnabled || cameraData.isSceneViewCamera @@ -217,7 +224,8 @@ private RenderPassInputSummary GetRenderPassInputs() || m_Renderer2DData.useCameraSortingLayerTexture || !Mathf.Approximately(cameraData.renderScale, 1.0f) || (DebugHandler != null && DebugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget)) - || cameraData.captureActions != null; + || cameraData.captureActions != null + || hasVolumetricShadowPass; return inputSummary; } diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl index 458024f290f..ddf6f32cbf2 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl @@ -59,8 +59,8 @@ if(intensity < 1)\ {\ half4 shadowTex = SAMPLE_TEXTURE2D(_ShadowTex, sampler_ShadowTex, input.shadowUV); \ - half4 shadowIntensity = 1-max(shadowTex.r, shadowTex.g * 1-shadowTex.b);\ - color.rgb = (color.rgb * shadowIntensity.rgb) + (color.rgb * intensity*(1 - shadowIntensity.rgb));\ + half shadowIntensity = 1 - max(shadowTex.r, shadowTex.g * (1 - shadowTex.b));\ + color.rgb = (color.rgb * shadowIntensity) + (color.rgb * intensity * (1 - shadowIntensity));\ } #define TRANSFER_SHADOWS(output)\ From afa2ab50770481484771a95b5af5ea50c1671c0e Mon Sep 17 00:00:00 2001 From: Roland Kindermann Date: Thu, 23 Apr 2026 16:28:40 +0000 Subject: [PATCH 41/56] Restore missing tooltips in Rendering Debugger fields (UUM-138920) --- .../com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs | 1 + 1 file changed, 1 insertion(+) 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 dcc7edc4f1e..0d41bab09b1 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.cs @@ -315,6 +315,7 @@ internal VisualElement ToVisualElement(Context context) } m_VisualElement.AddToClassList("unity-inspector-element"); m_VisualElement.name = displayName; + m_VisualElement.tooltip = tooltip; #if UNITY_EDITOR // Support for legacy state handling From 617dafe61d97f7749f3397d79a159f57654dbdc1 Mon Sep 17 00:00:00 2001 From: Kirill Titov Date: Thu, 23 Apr 2026 22:20:21 +0000 Subject: [PATCH 42/56] Compact resource versioning --- .../RenderGraph/RenderGraphTestsCore.cs | 27 ++-- .../RenderGraph/Compiler/ResourcesData.cs | 119 ++++++++++-------- .../RenderGraphDefaultResources.cs | 3 + .../NativePassCompilerRenderGraphTests.cs | 93 ++++++++------ .../RenderGraphTests.OnTileValidationLayer.cs | 14 +-- .../Tests/Editor/RenderGraphTests.cs | 6 +- .../Editor/RenderGraphTests.HelperPasses.cs | 6 +- 7 files changed, 148 insertions(+), 120 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs index 1314ca0e791..da06126293b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs @@ -1,13 +1,11 @@ using NUnit.Framework; using System; using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.Rendering.RenderGraphModule; -#if UNITY_EDITOR -using UnityEditor.Rendering; -#endif - -namespace UnityEngine.Rendering.Tests +namespace UnityEditor.Rendering.Tests { // TODO: Move this class to the Tests/Editor folder once the "IsolatedPackagesVerified" CI test correctly resolves all dependencies. // Currently, the URP package fails to locate the RenderGraphTestsCore class when it's placed under Tests/Editor, @@ -130,9 +128,8 @@ public void Setup() { // Setting default global settings to the custom RG render pipeline type, no quality settings so we can rely on the default RP m_RenderGraphTestGlobalSettings = ScriptableObject.CreateInstance(); -#if UNITY_EDITOR EditorGraphicsSettings.SetRenderPipelineGlobalSettingsAsset(m_RenderGraphTestGlobalSettings); -#endif + // Saving old render pipelines to set them back after testing m_OldDefaultRenderPipeline = GraphicsSettings.defaultRenderPipeline; m_OldQualityRenderPipeline = QualitySettings.renderPipeline; @@ -166,14 +163,20 @@ public void Cleanup() QualitySettings.renderPipeline = m_OldQualityRenderPipeline; m_OldQualityRenderPipeline = null; - m_RenderGraph.Cleanup(); + try + { + m_RenderGraph.Cleanup(); + } + catch (Exception e) + { + Debug.Log($"Tried to clean RenderGraph but exception was thrown: {e.Message}"); + } - Object.DestroyImmediate(m_RenderGraphTestPipeline); -#if UNITY_EDITOR + UnityEngine.Object.DestroyImmediate(m_RenderGraphTestPipeline); EditorGraphicsSettings.SetRenderPipelineGlobalSettingsAsset(null); -#endif - Object.DestroyImmediate(m_RenderGraphTestGlobalSettings); + + UnityEngine.Object.DestroyImmediate(m_RenderGraphTestGlobalSettings); GameObject.DestroyImmediate(m_GameObject); m_GameObject = null; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs index 1b5781e7b97..6be60eb445d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs @@ -24,13 +24,19 @@ public ResourceReaderData(int _passId, int _inputSlot) // RenderGraphResourceRegistry was identified as slow in the profiler internal struct ResourceUnversionedData { - public readonly bool isImported; // Imported graph resource - public bool isShared; // Shared graph resource - public int tag; + public int versionedDataOffset; // Where this resource's versioned data starts in the packed array + public int versionedDataCount; // Number of versions this resource actually has + public int readerDataOffset; // Where this resource's reader data starts in the packed array + public int maxReadersPerVersion; // Max readers across all versions of this resource + public int lastUsePassID; // Index of last used pass. The resource (if not imported) is destroyed after this pass. public int lastWritePassID; // The last pass writing it. After this other passes may still read the resource - public int firstUsePassID; //First pas using the resource this may be reading or writing. If not imported the resource is allocated just before this pass. + public int firstUsePassID; // First pass using the resource this may be reading or writing. If not imported the resource is allocated just before this pass. + public int latestVersionNumber; // Mostly readonly, can be decremented only if all passes using the last version are culled + + public readonly bool isImported; // Imported graph resource public bool memoryLess; // Never create the texture on GPU if it is allocated/freed within a renderpass + public int tag; public readonly int width; public readonly int height; @@ -38,8 +44,6 @@ internal struct ResourceUnversionedData public readonly int msaaSamples; public readonly GraphicsFormat graphicsFormat; - public int latestVersionNumber; // mostly readonly, can be decremented only if all passes using the last version are culled - public readonly bool clear; // graph.m_Resources.GetTextureResourceDesc(fragment.resource).clearBuffer; public readonly bool discard; // graph.m_Resources.GetTextureResourceDesc(fragment.resource).discardBuffer; public readonly bool bindMS; @@ -53,7 +57,6 @@ internal struct ResourceUnversionedData public ResourceUnversionedData(TextureResource rll, ref RenderTargetInfo info, ref TextureDesc desc, bool isResBackBuffer) { isImported = rll.imported; - isShared = false; tag = 0; firstUsePassID = -1; lastUsePassID = -1; @@ -73,6 +76,11 @@ public ResourceUnversionedData(TextureResource rll, ref RenderTargetInfo info, r isBackBuffer = isResBackBuffer; textureUVOrigin = rll.textureUVOrigin; graphicsFormat = desc.format; + + versionedDataOffset = 0; + versionedDataCount = 0; + readerDataOffset = 0; + maxReadersPerVersion = 0; } public ResourceUnversionedData(IRenderGraphResource rll, ref BufferDesc _, bool isResBackBuffer) @@ -80,7 +88,6 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref BufferDesc _, bool // We don't do anything with the BufferDesc for now. The compiler doesn't really need the details of the buffer like it does with textures // since for textures it needs the details to merge passes etc. Which is not relevant for buffers. isImported = rll.imported; - isShared = false; tag = 0; firstUsePassID = -1; lastUsePassID = -1; @@ -100,6 +107,11 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref BufferDesc _, bool isBackBuffer = isResBackBuffer; textureUVOrigin = TextureUVOriginSelection.Unknown; graphicsFormat = GraphicsFormat.None; + + versionedDataOffset = 0; + versionedDataCount = 0; + readerDataOffset = 0; + maxReadersPerVersion = 0; } public ResourceUnversionedData(IRenderGraphResource rll, ref RayTracingAccelerationStructureDesc _, bool isResBackBuffer) @@ -107,7 +119,6 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref RayTracingAccelerat // We don't do anything with the RayTracingAccelerationStructureDesc for now. The compiler doesn't really need the details of the acceleration structures like it does with textures // since for textures it needs the details to merge passes etc. Which is not relevant for acceleration structures. isImported = rll.imported; - isShared = false; tag = 0; firstUsePassID = -1; lastUsePassID = -1; @@ -127,6 +138,11 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref RayTracingAccelerat isBackBuffer = isResBackBuffer; textureUVOrigin = TextureUVOriginSelection.Unknown; graphicsFormat = GraphicsFormat.None; + + versionedDataOffset = 0; + versionedDataCount = 0; + readerDataOffset = 0; + maxReadersPerVersion = 0; } public void InitializeNullResource() @@ -167,11 +183,12 @@ public void SetWritingPass(CompilerContextData ctx, in ResourceHandle h, int pas public void RegisterReadingPass(CompilerContextData ctx, in ResourceHandle h, int passId, int index) { #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (numReaders >= ctx.resources.MaxReaders[h.iType]) + ref var unversioned = ref ctx.resources.unversionedData[h.iType].ElementAt(h.index); + if (numReaders >= unversioned.maxReadersPerVersion) { string passName = ctx.GetPassName(passId); string resourceName = ctx.GetResourceName(h); - throw new Exception($"Maximum '{ctx.resources.MaxReaders}' passes can use a single graph output as input. Pass {passName} is trying to read {resourceName}."); + throw new Exception($"Maximum '{unversioned.maxReadersPerVersion}' passes can use a single graph output as input. Pass {passName} is trying to read {resourceName}."); } #endif ctx.resources.readerData[h.iType][ctx.resources.IndexReader(h, numReaders)] = new ResourceReaderData(passId, index); @@ -203,16 +220,14 @@ public void RemoveReadingPass(CompilerContextData ctx, in ResourceHandle h, int } // This class allows quick lookups from ResourceHandle -> ResourceUnversionedData/ResourceVersionData/ResourceReaderData - // This is implementing a fully allocated array, we assume there aren't too many resources & versions. This lookup is fast and doesn't - // require GC allocs to fill. + // Uses resource-level sparse allocation: each resource allocates only the versions it needs. + // Reader allocation uses total read count as conservative upper bound (not true per-version sparse). + // Allocation metadata is inlined in ResourceUnversionedData for optimal cache performance. internal class ResourcesData { - public NativeList[] unversionedData; // Flattened fixed size array storing info per resource id shared between all versions. - public NativeList[] versionedData; // Flattened fixed size array storing up to MaxVersions versions per resource id. - public NativeList[] readerData; // Flattened fixed size array storing up to MaxReaders per resource id per version. - - public int[] MaxVersions; - public int[] MaxReaders; + public NativeList[] unversionedData; // Per-resource data (one per resource, includes allocation metadata) + public NativeList[] versionedData; // Packed versioned data (sparse) + public NativeList[] readerData; // Partially packed reader data (semi-sparse) public DynamicArray[] resourceNames; @@ -222,8 +237,6 @@ public ResourcesData() versionedData = new NativeList[(int)RenderGraphResourceType.Count]; readerData = new NativeList[(int)RenderGraphResourceType.Count]; resourceNames = new DynamicArray[(int)RenderGraphResourceType.Count]; - MaxVersions = new int[(int)RenderGraphResourceType.Count]; - MaxReaders = new int[(int)RenderGraphResourceType.Count]; for (int t = 0; t < (int)RenderGraphResourceType.Count; t++) resourceNames[t] = new DynamicArray(0); // T in NativeList cannot contain managed types, so the names are stored separately @@ -249,12 +262,10 @@ public void Clear() void AllocateAndResizeNativeListIfNeeded(ref NativeList nativeList, int size, NativeArrayOptions options) where T : unmanaged { // Allocate the first time or if Dispose() has been called through RenderGraph.Cleanup() - // Length remains 0, list is still empty if (!nativeList.IsCreated) nativeList = new NativeList(size, AllocatorManager.Persistent); // Resize the list (it will allocate if necessary) - // List is not empty anymore nativeList.Resize(size, options); } @@ -265,9 +276,6 @@ public void Initialize(RenderGraphResourceRegistry resources) RenderGraphResourceType resourceType = (RenderGraphResourceType) t; var numResources = resources.GetResourceCount(resourceType); - uint maxReaders = 0; - uint maxWriters = 0; - // We don't clear the list as we reinitialize it right after AllocateAndResizeNativeListIfNeeded(ref unversionedData[t], numResources, NativeArrayOptions.UninitializedMemory); @@ -281,16 +289,19 @@ public void Initialize(RenderGraphResourceRegistry resources) resourceNames[t][0] = new Name(""); } - // Fill the buffer with any existing external info requested for NRP RG process + // Compute allocation sizes and populate unversionedData in a single pass + int totalVersionedDataCount = 0; + int totalReaderDataCount = 0; + + // Null resource at index 0 already initialized to 0 in constructors + // Process all resources in one pass for better cache locality for (int r = 1; r < numResources; r++) { - // We cache these values here - // as getting them over and over from other - // graph data structures external to NRP RG is costly var h = new ResourceHandle(r, resourceType, false); var rll = resources.GetResourceLowLevel(h); resourceNames[t][r] = new Name(rll.GetName()); + // Initialize unversionedData based on resource type switch (t) { case (int)RenderGraphResourceType.Texture: @@ -325,49 +336,57 @@ public void Initialize(RenderGraphResourceRegistry resources) throw new Exception("Unsupported resource type: " + t); } - maxReaders = Math.Max(maxReaders, rll.readCount); - maxWriters = Math.Max(maxWriters, rll.writeCount); + // Compute allocation metadata for this resource + // +1 for versions: v0 exists even without writes + int numVersions = (int)rll.writeCount + 1; + // +1 for readers: transient resources don't call IncrementReadCount, but BuildGraph adds 1 implicit read + // Note: rll.readCount is total across all versions (not per-version), so this is a conservative upper bound + int numReaders = (int)rll.readCount + 1; + + // Populate allocation metadata + ref var unversioned = ref unversionedData[t].ElementAt(r); + unversioned.versionedDataOffset = totalVersionedDataCount; + unversioned.versionedDataCount = numVersions; + unversioned.readerDataOffset = totalReaderDataCount; + unversioned.maxReadersPerVersion = numReaders; + + totalVersionedDataCount += numVersions; + totalReaderDataCount += numVersions * numReaders; } - // The first resource is a null resource, so we need to add 1 to the count. - MaxReaders[t] = (int)maxReaders + 1; - MaxVersions[t] = (int)maxWriters + 1; - - // Clear the other caching structures, they will be filled later - AllocateAndResizeNativeListIfNeeded(ref versionedData[t], MaxVersions[t] * numResources, NativeArrayOptions.ClearMemory); - AllocateAndResizeNativeListIfNeeded(ref readerData[t], MaxVersions[t] * MaxReaders[t] * numResources, NativeArrayOptions.ClearMemory); + AllocateAndResizeNativeListIfNeeded(ref versionedData[t], totalVersionedDataCount, NativeArrayOptions.ClearMemory); + AllocateAndResizeNativeListIfNeeded(ref readerData[t], totalReaderDataCount, NativeArrayOptions.ClearMemory); } } - // Flatten array index + // Flatten array index using sparse allocation (uses inlined allocation metadata) [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Index(in ResourceHandle h) { + ref var unversioned = ref unversionedData[h.iType].ElementAt(h.index); #if UNITY_EDITOR // Hot path - if (h.version < 0 || h.version >= MaxVersions[h.iType]) + if (h.version < 0 || h.version >= unversioned.versionedDataCount) throw new Exception("Invalid version: " + h.version); #endif - return h.index * MaxVersions[h.iType] + h.version; + return unversioned.versionedDataOffset + h.version; } - // Flatten array index + // Flatten array index for readers using sparse allocation (uses inlined allocation metadata) [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexReader(in ResourceHandle h, int readerID) { + ref var unversioned = ref unversionedData[h.iType].ElementAt(h.index); #if UNITY_EDITOR // Hot path - if (h.version < 0 || h.version >= MaxVersions[h.iType]) + if (h.version < 0 || h.version >= unversioned.versionedDataCount) throw new Exception("Invalid version"); - if (readerID < 0 || readerID >= MaxReaders[h.iType]) + if (readerID < 0 || readerID >= unversioned.maxReadersPerVersion) throw new Exception("Invalid reader"); #endif - return (h.index * MaxVersions[h.iType] + h.version) * MaxReaders[h.iType] + readerID; + return unversioned.readerDataOffset + h.version * unversioned.maxReadersPerVersion + readerID; } // Lookup data for a given handle - public ref ResourceVersionedData this[ResourceHandle h] - { - get { return ref versionedData[h.iType].ElementAt(Index(h)); } - } + public ref ResourceVersionedData this[ResourceHandle h] => ref versionedData[h.iType].ElementAt(Index(h)); public void Dispose() { 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 f3e9b8a7f82..524a66f89d0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs @@ -80,6 +80,9 @@ internal void InitializeForRendering(RenderGraph renderGraph) whiteTexture = renderGraph.ImportTexture(m_WhiteTexture2D, true); defaultShadowTexture = renderGraph.ImportTexture(m_ShadowTexture2D, true); + if (!TextureXR.initialized) + return; + clearTextureXR = renderGraph.ImportTexture(TextureXR.GetClearTexture(), true); magentaTextureXR = renderGraph.ImportTexture(TextureXR.GetMagentaTexture(), true); blackTextureXR = renderGraph.ImportTexture(TextureXR.GetBlackTexture(), true); diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs index b8a52e84ae6..4cd9f58fa40 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs @@ -1101,13 +1101,13 @@ public void MaxReadersAndMaxVersionsAreCorrectForBuffers() var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); - // The resource with the biggest MaxReaders is buffer2: - // 1 implicit read (TestPass0) + 1 explicit read (TestPass1) + 1 for the offset. - Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 3); - - // The resource with the biggest MaxVersion is buffer2: - // 1 explicit write (TestPass0) + 1 explicit readwrite (TestPass1) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 3); + // Verify sparse allocation works: buffer2 should have per-resource allocation metadata inlined in unversionedData + // buffer2: 1 explicit write (TestPass0) + 1 explicit readwrite (TestPass1) + 1 for v0 = 3 versions + // buffer2: 1 implicit read (TestPass0) + 1 explicit read (TestPass1) + 1 for implicit transient reads = 3 readers + var buffer2Handle = buffer2.handle; + ref var buffer2Unversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Buffer].ElementAt(buffer2Handle.index); + Assert.AreEqual(3, buffer2Unversioned.versionedDataCount, "buffer2 should have 3 versions allocated"); + Assert.AreEqual(3, buffer2Unversioned.maxReadersPerVersion, "buffer2 should have 3 max readers per version"); } [Test] @@ -1142,13 +1142,18 @@ public void MaxReadersAndMaxVersionsAreCorrectForTextures() var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); - // Resources with the biggest MaxReaders are extraTextures[0] and depthBuffer (both being equal): - // 1 implicit read (TestPass0) + 2 explicit read (TestPass1 & TestPass2) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture], 4); - - // The resource with the biggest MaxVersion is extraTextures[0]: - // 1 explicit write (TestPass0) + 1 explicit read-write (TestPass1) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture], 3); + // Verify sparse allocation: extraTextures[0] should have proper per-resource allocation inlined in unversionedData + // extraTextures[0]: 1 explicit write (TestPass0) + 1 explicit read-write (TestPass1) + 1 for v0 = 3 versions + // extraTextures[0]: 1 implicit read (TestPass0) + 2 explicit read (TestPass1 & TestPass2) + 1 for implicit transient reads = 4 readers + var extraTex0Handle = renderTargets.extraTextures[0].handle; + ref var extraTex0Unversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Texture].ElementAt(extraTex0Handle.index); + Assert.AreEqual(3, extraTex0Unversioned.versionedDataCount, "extraTextures[0] should have 3 versions allocated"); + Assert.AreEqual(4, extraTex0Unversioned.maxReadersPerVersion, "extraTextures[0] should have 4 max readers per version"); + + // Verify depthBuffer has its own allocation (only used by TestPass0 and TestPass1) + var depthHandle = renderTargets.depthBuffer.handle; + ref var depthUnversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Texture].ElementAt(depthHandle.index); + Assert.AreEqual(3, depthUnversioned.maxReadersPerVersion, "depthBuffer should have 3 max readers per version (sparse allocation)"); } [Test] @@ -1184,13 +1189,13 @@ public void MaxReadersAndMaxVersionsAreCorrectForBuffersMultiplePasses() var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); - // The resource with the biggest MaxReaders is buffer2: - // 5 implicit read (TestPass0-2-4-6-8) + 5 explicit read (TestPass1-3-5-7-9) + 1 for the offset. - Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 11); - - // The resource with the biggest MaxVersion is buffer2: - // 5 explicit write (TestPass0-2-4-6-8) + 5 explicit readwrite (TestPass1-3-5-7-9) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 11); + // Verify sparse allocation: buffer2 should have per-resource allocation metadata inlined in unversionedData + // buffer2: 5 explicit write (TestPass0-2-4-6-8) + 5 explicit readwrite (TestPass1-3-5-7-9) + 1 for v0 = 11 versions + // buffer2: 5 implicit read (TestPass0-2-4-6-8) + 5 explicit read (TestPass1-3-5-7-9) + 1 for implicit transient reads = 11 readers + var buffer2Handle = buffer2.handle; + ref var buffer2Unversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Buffer].ElementAt(buffer2Handle.index); + Assert.AreEqual(11, buffer2Unversioned.versionedDataCount, "buffer2 should have 11 versions allocated"); + Assert.AreEqual(11, buffer2Unversioned.maxReadersPerVersion, "buffer2 should have 11 max readers per version"); } [Test] @@ -1243,31 +1248,37 @@ public void ResourcesData_MaxReadersAndVersionsPerResourceType() var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); var passes = result.contextData.GetNativePasses(); - // VERIFY: MaxReaders and MaxVersions are calculated PER RESOURCE TYPE - // TEXTURE TYPE: - // 2 readwrite operations = 2 versions + 1 offset = 3 versions/readers. - Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture], 3); - Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture], 3); - - // BUFFER TYPE: - // 5 write operations + 5 readwrite operations = 10 versions + 1 offset = 11 versions/readers. - Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 11); - Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 11); - - // VERIFY: Index calculations work correctly with per-type maximums + // VERIFY: Sparse allocation allocates per-resource based on actual usage (inlined in unversionedData) + // TEXTURE TYPE: extraTextures[0] + // 2 readwrite operations = 2 versions + 1 for v0 = 3 versions + // 2 implicit reads + 0 explicit reads + 1 for implicit transient reads = 3 readers + var extraTex0Handle = renderTargets.extraTextures[0].handle; + ref var extraTex0Unversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Texture].ElementAt(extraTex0Handle.index); + Assert.AreEqual(3, extraTex0Unversioned.versionedDataCount, "extraTextures[0] should have 3 versions allocated"); + Assert.AreEqual(3, extraTex0Unversioned.maxReadersPerVersion, "extraTextures[0] should have 3 max readers per version"); + + // BUFFER TYPE: buffer + // 5 write operations + 5 readwrite operations = 10 versions + 1 for v0 = 11 versions + // 5 implicit reads + 5 explicit reads + 1 for implicit transient reads = 11 readers + var bufferHandle = buffer.handle; + ref var bufferUnversioned = ref result.contextData.resources.unversionedData[(int)RenderGraphResourceType.Buffer].ElementAt(bufferHandle.index); + Assert.AreEqual(11, bufferUnversioned.versionedDataCount, "buffer should have 11 versions allocated"); + Assert.AreEqual(11, bufferUnversioned.maxReadersPerVersion, "buffer should have 11 max readers per version"); + + // VERIFY: Index calculations work correctly with sparse allocation // Get the texture handle from the first native pass attachment var textureHandle = passes[0].attachments[0].handle; Assert.AreEqual(renderTargets.extraTextures[0].handle.index, passes[0].attachments[0].handle.index); - // Test Index() calculation uses correct MaxVersions for texture type - int indexExpected = textureHandle.index * result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture] + textureHandle.version; - Assert.AreEqual(result.contextData.resources.Index(textureHandle), indexExpected); - Assert.IsTrue(indexExpected < result.contextData.resources.versionedData[(int)RenderGraphResourceType.Texture].Capacity); + // Test Index() returns valid indices within bounds (sparse allocation uses per-resource offsets) + int actualIndex = result.contextData.resources.Index(textureHandle); + Assert.IsTrue(actualIndex >= 0); + Assert.IsTrue(actualIndex < result.contextData.resources.versionedData[(int)RenderGraphResourceType.Texture].Length); - // Test IndexReader() calculation uses correct MaxReaders for texture type - int indexReaderExpected = indexExpected * result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture] + 0; - Assert.AreEqual(result.contextData.resources.IndexReader(textureHandle, 0), indexReaderExpected); - Assert.IsTrue(indexExpected < result.contextData.resources.readerData[(int)RenderGraphResourceType.Texture].Capacity); + // Test IndexReader() returns valid indices within bounds (sparse allocation uses per-resource offsets) + int actualReaderIndex = result.contextData.resources.IndexReader(textureHandle, 0); + Assert.IsTrue(actualReaderIndex >= 0); + Assert.IsTrue(actualReaderIndex < result.contextData.resources.readerData[(int)RenderGraphResourceType.Texture].Length); } [Test] diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.OnTileValidationLayer.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.OnTileValidationLayer.cs index 67f195c8a62..807db7e78df 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.OnTileValidationLayer.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.OnTileValidationLayer.cs @@ -1,16 +1,12 @@ using NUnit.Framework; using UnityEngine.Rendering.RenderGraphModule; using Unity.RenderPipelines.Core.Runtime.Shared; - -#if UNITY_EDITOR -using UnityEditor; -using UnityEditor.Rendering; -#endif +using UnityEditor.Rendering.Tests; namespace UnityEngine.Rendering.Tests { internal partial class RenderGraphTests : RenderGraphTestsCore - { + { TextureHandle CreateTextureHandle() { var desc = new TextureDesc(16, 16); @@ -281,10 +277,10 @@ public void OnTileValidationLayer_SetGlobalTextureAfterPassThrows() { var validationLayer = CreateValidationLayer(); - var tex = CreateTextureHandle(); + var tex = CreateTextureHandle(); + + validationLayer.Add(tex); - validationLayer.Add(tex); - Assert.Catch(() => { using (var builder = m_RenderGraph.AddRasterRenderPass("Raster 1", out OnTileValidationTestData passData)) 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 686246ad4e8..71b2ee329a8 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs @@ -5,13 +5,11 @@ using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.TestTools; using Unity.Collections; +using UnityEditor.Rendering.Tests; using UnityEngine.Rendering.RendererUtils; using UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler; - -#if UNITY_EDITOR using UnityEditor; -using UnityEditor.Rendering; -#endif + namespace UnityEngine.Rendering.Tests { [InitializeOnLoad] diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/RenderGraphTests.HelperPasses.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/RenderGraphTests.HelperPasses.cs index f1fa2db980f..5436710aac2 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/RenderGraphTests.HelperPasses.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/RenderGraphTests.HelperPasses.cs @@ -1,13 +1,11 @@ using NUnit.Framework; using UnityEngine.Experimental.Rendering; using Unity.Collections; +using UnityEditor.Rendering.Tests; using UnityEngine.Rendering.RenderGraphModule.Util; using UnityEngine.Rendering.Universal; using static UnityEngine.Rendering.RenderGraphModule.Util.RenderGraphUtils; - -#if UNITY_EDITOR using UnityEditor.Rendering; -#endif namespace UnityEngine.Rendering.Tests { @@ -19,7 +17,7 @@ public void OneTimeSetup() if (!(GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset)) Assert.Ignore("Current pipeline is not URP. Skipping tests..."); } - + static GraphicsFormat[] depthBlitTestFormats = { GraphicsFormat.D32_SFloat, From d7fb00d2f5136ebe8c5bc9a48523a9a8798f1b0d Mon Sep 17 00:00:00 2001 From: Cian Noonan Date: Thu, 23 Apr 2026 22:20:22 +0000 Subject: [PATCH 43/56] Selection History --- .../Editor/Drawing/Blackboard/SGBlackboard.cs | 5 + .../Editor/Drawing/Views/GraphEditorView.cs | 109 +++++++++++++++++- .../Editor/Drawing/Views/MaterialGraphView.cs | 4 +- .../GraphView/Blackboard/VFXBlackboard.cs | 7 +- .../Editor/GraphView/Views/VFXView.cs | 86 +++++++++++--- .../CommonAssets/Editor/PropertyTests.cs | 73 +++++++++++- .../Editor/Tests/VFXBlackboardTests.cs | 60 ++++++++++ 7 files changed, 326 insertions(+), 18 deletions(-) diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs index 8dfff8b1d17..6e01734fa45 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs @@ -623,5 +623,10 @@ public override void Dispose() m_ScrollBoundaryTop = null; m_PathLabelTextField = null; } + + internal void ScrollToItem(VisualElement ve) + { + m_ScrollView.ScrollTo(ve); + } } } diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Views/GraphEditorView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Views/GraphEditorView.cs index f91d63a1f63..2f303d3f8e7 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Views/GraphEditorView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Views/GraphEditorView.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using UnityEngine; +using UnityEditor; using UnityEditor.Graphing; using UnityEditor.Graphing.Util; using UnityEditor.ShaderGraph.Drawing.Inspector; @@ -523,6 +523,8 @@ void CreateMasterPreview() m_MasterPreviewView.onResized += UpdateSerializedWindowLayout; } + const string kSelectionKey = "Unity.ShaderGraphHistory"; + void CreateInspector() { var inspectorViewModel = new InspectorViewModel() { parentView = this.graphView }; @@ -530,6 +532,111 @@ void CreateInspector() graphView.OnSelectionChange += m_InspectorView.TriggerInspectorUpdate; // Undo/redo actions that only affect selection don't trigger the above callback for some reason, so we also have to do this Undo.undoRedoPerformed += (() => { m_InspectorView?.TriggerInspectorUpdate(graphView?.selection); }); + + graphView.OnSelectionChange += RecordSelectionHistory; + Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler, CustomValidator); + } + + static bool CustomValidator(string data, EditorWindow sourceWindow) + { + if (sourceWindow == null || sourceWindow is not MaterialGraphEditWindow graphWindow) return false; + + var graphView = graphWindow.graphEditorView?.m_GraphView; + if (graphView == null) return false; + + var info = GraphSelection.FromJson(data); + if (info == null) return false; + + foreach (var id in info.elements) + { + if (graphView.GetElementByGuid(id) != null) return true; + } + + return false; + } + + bool m_ApplyingCustomSelection; + static void CustomSelectionHandler(string data, EntityId[] _) + { + var info = GraphSelection.FromJson(data); + if (info == null) return; + + var window = EditorWindow.focusedWindow as MaterialGraphEditWindow; + var graphEditorView = window?.graphEditorView; + var graphView = graphEditorView?.m_GraphView; + if (graphView == null) return; + + var blackboard = window.graphEditorView.blackboardController?.blackboard; + var fields = ListPool.Get(); + foreach (var id in info.elements) + { + var e = graphView.GetElementByGuid(id); + if (e is SGBlackboardField field) + { + blackboard?.ScrollToItem(field); + fields.Add(field); + } + } + + if (fields.Count > 0) + { + EditorApplication.delayCall += () => + { + try + { + graphEditorView.m_ApplyingCustomSelection = true; + // info.ApplyToGraphView may have added this element to selection, before our delayCall executes, avoid duplication + foreach(var e in fields) + { + if (e != null && !graphView.selection.Contains(e)) graphView.AddToSelectionNoUndoRecord(e); + } + + ListPool.Release(fields); + } + finally + { + graphEditorView.m_ApplyingCustomSelection = false; + } + }; + } + else + { + ListPool.Release(fields); + } + + try + { + graphEditorView.m_ApplyingCustomSelection = true; + info.ApplyToGraphView(graphView, null); + window.graphEditorView.m_InspectorView.TriggerInspectorUpdate(graphView.selection); + } + finally + { + graphEditorView.m_ApplyingCustomSelection = false; + } + } + + void RecordSelectionHistory(IEnumerable selectionList) + { + if (m_ApplyingCustomSelection || m_GraphView == null || m_GraphView.graph == null) + return; + var info = new GraphSelection(); + foreach (var sel in selectionList) + { + if (sel is not GraphElement e) + continue; + // In some cases (e.g. window is being hidden), elements are removed from selection, + // but selection changed callback is invoked with the old selection set. The elements + // themselves are un-selected already though. Skip over those. + if (!e.selected) + continue; + info.elements.Add(e.viewDataKey); + } + + if (info.isEmpty) + return; + + Selection.SetCustomSelection(kSelectionKey, EditorJsonUtility.ToJson(info)); } // a nice curve that scales well for various HID (touchpad and mice). diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs index 8e96e73c531..832cf6b6162 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs @@ -535,7 +535,7 @@ public override void AddToSelection(ISelectable selectable) } // Replicating these private GraphView functions as we need them for our own purposes - internal void AddToSelectionNoUndoRecord(GraphElement graphElement) + internal new void AddToSelectionNoUndoRecord(GraphElement graphElement) { graphElement.selected = true; selection.Add(graphElement); @@ -584,7 +584,7 @@ public override void ClearSelection() OnSelectionChange?.Invoke(selection); } - internal bool ClearSelectionNoUndoRecord() + internal new bool ClearSelectionNoUndoRecord() { foreach (var graphElement in selection.OfType()) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs index fd1c53ee866..5469951996c 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs @@ -374,7 +374,6 @@ private void OnSelectionChanged(IEnumerable selectedItems) } } } - private DragVisualMode OnHandleDrop(HandleDragAndDropArgs arg) { if (arg.parentId < 0) @@ -1562,5 +1561,11 @@ private string FilterOutReservedCategoryName(string category) return category; } + + internal void ScrollToItem(string itemName) + { + var treeviewItem = m_ParametersController.SelectMany(GetDataRecursive).Single(x => string.Compare(x.data.title, itemName, StringComparison.OrdinalIgnoreCase) == 0); + m_Treeview.ScrollToItemById(treeviewItem.id); + } } } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXView.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXView.cs index f1c80cc3e3b..0fb809e94ea 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXView.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXView.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.ObjectModel; using System.Collections.Generic; @@ -16,7 +17,9 @@ using UnityEngine.VFX; using UnityEngine.UIElements; using UnityEditor.UIElements; +using UnityEngine.Pool; using UnityEngine.Profiling; +using Object = UnityEngine.Object; using PositionType = UnityEngine.UIElements.Position; using Task = UnityEditor.VersionControl.Task; @@ -221,6 +224,8 @@ void DisconnectController(VFXViewController previousController) OnFocus(); } + const string kSelectionKey = "Unity.VisualEffectGraphHistory"; + void ConnectController() { schedule.Execute(() => @@ -253,6 +258,49 @@ void ConnectController() } SceneView.duringSceneGui += OnSceneGUI; + Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler); + } + + static void CustomSelectionHandler(string data, EntityId[] _) + { + var info = GraphSelection.FromJson(data); + if (info == null) return; + + var window = EditorWindow.focusedWindow as VFXViewWindow; + var graphView = window?.graphView; + if (graphView?.controller == null) return; + + var blackboard = graphView.blackboard; + var elements = ListPool.Get(); + foreach (var id in info.elements) + { + var e = graphView.GetElementByGuid(id); + if (e is VFXBlackboardField || e is VFXBlackboardAttributeField) + { + var tokens = id.Split(':', StringSplitOptions.RemoveEmptyEntries); + blackboard.ScrollToItem(tokens.Length == 1 ? tokens[0] : tokens[1]); + elements.Add(e); + } + } + + if (elements.Count > 0) + { + EditorApplication.delayCall += () => + { + // info.ApplyToGraphView may have added this element to selection, before our delayCall executes, avoid duplication + foreach (var e in elements) + { + if (e != null && !graphView.selection.Contains(e)) graphView.AddToSelectionNoUndoRecord(e); + } + ListPool.Release(elements); + }; + } + else + { + ListPool.Release(elements); + } + + info.ApplyToGraphView(graphView, graphView.blackboard); } IEnumerable GetAcceptedTypeNodes() @@ -509,7 +557,7 @@ public static VisualTreeAsset LoadUXML(string text) public static Texture2D LoadImage(string text) { - string path = string.Format("{0}/VFX/{1}.png", VisualEffectAssetEditorUtility.editorResourcesPath, text); + string path = $"{VisualEffectAssetEditorUtility.editorResourcesPath}/VFX/{text}.png"; return EditorGUIUtility.LoadIcon(path); } @@ -2087,38 +2135,50 @@ public void UpdateGlobalSelection() { if (controller == null) return; - var objectsSelected = new List(); + using var _ = ListPool.Get(out var objectsSelected); + var sel = new GraphSelection(); var emptyBlackboardSelection = false; foreach (var element in selection) { switch (element) { case VFXNodeUI nodeUI: - if (nodeUI.controller.model != null) + var nodeModel = nodeUI.controller.model; + if (nodeModel != null) { - objectsSelected.Add(nodeUI.controller.model); + objectsSelected.Add(nodeModel.GetEntityId()); + sel.elements.Add(nodeUI.viewDataKey); emptyBlackboardSelection = true; } break; case VFXBlackboardField blackboardField: - if (blackboardField.controller.model != null) + var blackboardModel = blackboardField.controller.model; + if (blackboardModel != null) { - objectsSelected.Add(blackboardField.controller.model); + objectsSelected.Add(blackboardModel.GetEntityId()); + sel.elements.Add(blackboardField.viewDataKey); } break; - case VFXBlackboardAttributeField aField: - var attributeField = aField; + case VFXBlackboardAttributeField attributeField: var customAttribute = controller.graph.customAttributes.SingleOrDefault(x => string.Compare(attributeField.text, x.attributeName, StringComparison.OrdinalIgnoreCase) == 0); - objectsSelected.Add(customAttribute); - break; - case VFXBlackboardCategory category: + if (customAttribute != null) objectsSelected.Add(customAttribute.GetEntityId()); + sel.elements.Add(attributeField.viewDataKey); break; } } - if (objectsSelected.Count > 0) + if (sel.elements.Count > 0) { - Selection.objects = objectsSelected.ToArray(); + var rentedArray = ArrayPool.Shared.Rent(objectsSelected.Count); + try + { + objectsSelected.CopyTo(rentedArray, 0); + Selection.SetCustomSelection(kSelectionKey, EditorJsonUtility.ToJson(sel), rentedArray); + } + finally + { + ArrayPool.Shared.Return(rentedArray, clearArray: false); + } if (emptyBlackboardSelection) { blackboard.EmptySelection(); diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/PropertyTests.cs b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/PropertyTests.cs index 159827a190f..7ed8b0b7e96 100644 --- a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/PropertyTests.cs +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Editor/PropertyTests.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using UnityEngine; using UnityEditor.ShaderGraph.Drawing; using UnityEditor.ShaderGraph.Internal; using UnityEditor.ShaderGraph.UnitTests.Controllers; +using UnityEngine; using UnityEngine.TestTools; using UnityEngine.UIElements; @@ -125,6 +125,77 @@ public IEnumerator ResetPropertyReference() } } + [UnityTest] + public IEnumerator BlackboardSelectionHistory() + { + Assert.IsNotNull(m_BlackboardTestController.addBlackboardItemsMenu, "Blackboard Add Items menu reference owned by BlackboardTestController is null."); + + var menuItems = m_BlackboardTestController.addBlackboardItemsMenu.GetPrivateProperty("menuItems"); + Assert.IsNotNull(menuItems, "Could not retrieve reference to the menu items of the Blackboard Add Items menu"); + + for (int i = 0; i < 6; i++) + { + var item = menuItems[i]; + var menuFunction = item.GetNonPrivateField("func"); + menuFunction?.Invoke(); + yield return null; + } + + var fieldViewElements = m_GraphEditorView.Query("SGBlackboardField"); + var elementList = fieldViewElements.ToList(); + + var selectionOrder = new List(elementList.Count); + + for (int i = 0; i < elementList.Count - 1; i++) + { + var visualElement = elementList[i]; + if (visualElement is not SGBlackboardField blackboardPropertyView) continue; + + selectionOrder.Add(blackboardPropertyView); + + m_GraphEditorView.graphView.ClearSelection(); + m_GraphEditorView.graphView.AddToSelection(blackboardPropertyView); + Undo.IncrementCurrentGroup(); + + yield return null; + } + + var lastSelection = selectionOrder[^1]; + var currentSelection = m_GraphEditorView.graphView.selection[0]; + + Assert.AreEqual(lastSelection, currentSelection); + + EditorApplication.ExecuteMenuItem("Edit/Previous Selection"); + yield return null; + + var secondToLastSelection = selectionOrder[^2]; + currentSelection = m_GraphEditorView.graphView.selection[0]; + + Assert.AreEqual(secondToLastSelection, currentSelection); + + EditorApplication.ExecuteMenuItem("Edit/Previous Selection"); + yield return new WaitForSecondsRealtime(0.1f); + + var thirdToLastSelection = selectionOrder[^3]; + currentSelection = m_GraphEditorView.graphView.selection[0]; + + Assert.AreEqual(thirdToLastSelection, currentSelection); + + EditorApplication.ExecuteMenuItem("Edit/Next Selection"); + yield return null; + + currentSelection = m_GraphEditorView.graphView.selection[0]; + + Assert.AreEqual(secondToLastSelection, currentSelection); + + EditorApplication.ExecuteMenuItem("Edit/Next Selection"); + yield return null; + + currentSelection = m_GraphEditorView.graphView.selection[0]; + + Assert.AreEqual(lastSelection, currentSelection); + } + [UnityTest] public IEnumerator AddInputTests() { diff --git a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXBlackboardTests.cs b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXBlackboardTests.cs index 353c12c573d..36522ecd922 100644 --- a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXBlackboardTests.cs +++ b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXBlackboardTests.cs @@ -33,7 +33,67 @@ public void OneTimeCleanup() VFXViewWindow.GetAllWindows().ToList().ForEach(x => x.Close()); VFXTestCommon.DeleteAllTemporaryGraph(); } + [UnityTest] + public IEnumerator Select_Parameter_RecordsToHistory_AndCanNavigate() + { + // Arrange + BoardPreferenceHelper.SetVisible(BoardPreferenceHelper.Board.blackboard, true); + var graph = VFXTestCommon.MakeTemporaryGraph(); + var window = VFXViewWindow.GetWindow(graph, true); + window.LoadResource(graph.visualEffectResource); + VFXBlackboard blackboard = window.graphView.blackboard; + yield return null; + blackboard.Update(); + yield return null; + + var paramDescArray = VFXLibrary.GetParameters().ToArray(); + for (int i = 0; i < paramDescArray.Length; i++) + { + AddParameter(blackboard, paramDescArray[i]); + } + + yield return null; + blackboard.Focus(); + yield return null; + // Act + VFXBlackboardField parameterFieldFirst = null; + VFXBlackboardField parameterFieldLast = null; + var maxFrames = 16; + while (parameterFieldFirst == null && parameterFieldLast == null && maxFrames-- > 0) + { + yield return null; + parameterFieldFirst = blackboard.Query().First(); + parameterFieldLast = blackboard.Query().Last(); + } + Assert.NotNull(parameterFieldFirst); + Assert.NotNull(parameterFieldLast); + + SelectionHistory.instance.ClearHistory(); + window.graphView.AddToSelection(parameterFieldFirst); + Undo.IncrementCurrentGroup(); + yield return null; + + // Assert + Assert.IsTrue(SelectionHistory.instance.GetHistory().Count == 1); + + window.graphView.ClearSelection(); + yield return null; + + window.graphView.AddToSelection(parameterFieldLast); + Undo.IncrementCurrentGroup(); + yield return null; + + Assert.IsTrue(SelectionHistory.instance.GetHistory().Count == 2); + var currentSelection = SelectionHistory.instance.GetHistory()[SelectionHistory.instance.GetIndex()]; + Assert.IsTrue(currentSelection.m_CustomData.Contains(parameterFieldLast.PropertyItem.title)); + + SelectionHistory.instance.GoBack(); + yield return null; + + currentSelection = SelectionHistory.instance.GetHistory()[SelectionHistory.instance.GetIndex()]; + Assert.IsTrue(currentSelection.m_CustomData.Contains(parameterFieldFirst.PropertyItem.title)); + } [UnityTest] public IEnumerator Add_Category() { From 3b933ec0a39d07c6d558a7bc97d079cd783a8820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SeungChan=20Jeong=20=EF=BC=88=EC=A0=95=EC=8A=B9=EC=B0=AC?= =?UTF-8?q?=EF=BC=89?= Date: Thu, 23 Apr 2026 22:20:27 +0000 Subject: [PATCH 44/56] Add graphics test for Modern SSAO --- .../ShaderLibrary/SSAO.hlsl | 2 +- .../URPAssets/DefaultURPAsset.asset | 19 ++- .../Assets/Scenes/150_TAA/150_ResetHistory.cs | 14 ++ .../Scenes/150_TAA/150_ResetHistory.cs.meta | 2 + .../Assets/Scenes/150_TAA_RT.unity | 4 +- .../Scenes/150_TAA_RT_AlphaOutput.unity | 4 +- .../Assets/Scenes/500_SSAO.meta | 8 + .../Scenes/500_SSAO/Legacy_BN_High.json | 118 +++++++++++++ .../Scenes/500_SSAO/Legacy_BN_High.json.meta | 7 + .../Scenes/500_SSAO/Legacy_BN_Medium.json | 118 +++++++++++++ .../500_SSAO/Legacy_BN_Medium.json.meta | 7 + .../Scenes/500_SSAO/Legacy_IGN_High.json | 118 +++++++++++++ .../Scenes/500_SSAO/Legacy_IGN_High.json.meta | 7 + .../500_SSAO/Legacy_IGN_High_Downsample.json | 118 +++++++++++++ .../Legacy_IGN_High_Downsample.json.meta | 7 + .../500_SSAO/Legacy_IGN_Low_DepthOnly.json | 118 +++++++++++++ .../Legacy_IGN_Low_DepthOnly.json.meta | 7 + .../Scenes/500_SSAO/Legacy_IGN_Medium.json | 118 +++++++++++++ .../500_SSAO/Legacy_IGN_Medium.json.meta | 7 + .../Assets/Scenes/500_SSAO/SSAO_BN_High.asset | 83 ++++++++++ .../Scenes/500_SSAO/SSAO_BN_High.asset.meta | 8 + .../Scenes/500_SSAO/SSAO_BN_Medium.asset | 83 ++++++++++ .../Scenes/500_SSAO/SSAO_BN_Medium.asset.meta | 8 + .../Scenes/500_SSAO/SSAO_IGN_High.asset | 83 ++++++++++ .../Scenes/500_SSAO/SSAO_IGN_High.asset.meta | 8 + .../500_SSAO/SSAO_IGN_Low_DepthOnly.asset | 83 ++++++++++ .../SSAO_IGN_Low_DepthOnly.asset.meta | 8 + .../Scenes/500_SSAO/SSAO_IGN_Medium.asset | 83 ++++++++++ .../500_SSAO/SSAO_IGN_Medium.asset.meta | 8 + .../Assets/Scenes/500_SSAO/bluenoise.png | 3 + .../Assets/Scenes/500_SSAO/bluenoise.png.meta | 117 +++++++++++++ .../Assets/Scenes/500_SSAO/depth.exr | 3 + .../Assets/Scenes/500_SSAO/depth.exr.meta | 117 +++++++++++++ .../Assets/Scenes/500_SSAO/normals.png | 3 + .../Assets/Scenes/500_SSAO/normals.png.meta | 156 ++++++++++++++++++ 35 files changed, 1649 insertions(+), 8 deletions(-) create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png.meta diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl index 4945b8f145a..d2a9859c9f3 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl @@ -200,7 +200,7 @@ float3 ReconstructViewPos(float2 uv, float linearDepth) viewPos *= zScale; #endif - return half3(viewPos); + return viewPos; } // Try reconstructing normal accurately from depth buffer. diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/CommonAssets/URPAssets/DefaultURPAsset.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/CommonAssets/URPAssets/DefaultURPAsset.asset index 90534f1b3d4..b9ce13eaa14 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/CommonAssets/URPAssets/DefaultURPAsset.asset +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/CommonAssets/URPAssets/DefaultURPAsset.asset @@ -12,8 +12,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} m_Name: DefaultURPAsset m_EditorClassIdentifier: - k_AssetVersion: 12 - k_AssetPreviousVersion: 12 + k_AssetVersion: 13 + k_AssetPreviousVersion: 13 m_RendererType: 1 m_RendererData: {fileID: 0} m_RendererDataList: @@ -30,6 +30,11 @@ MonoBehaviour: - {fileID: 11400000, guid: 7c7a4f27be43bd847a58021195aeadb0, type: 2} - {fileID: 11400000, guid: b347de46caf7551439f5930790d3c0f6, type: 2} - {fileID: 11400000, guid: 2724f69ce5c29884cbddc10513ecb4ab, type: 2} + - {fileID: 11400000, guid: 597b9f1a0b1557c448178217c078d942, type: 2} + - {fileID: 11400000, guid: cd2ef63e3ab2d8040b42e100d9ecd08b, type: 2} + - {fileID: 11400000, guid: 6c7f4485aa22e9c4e984f7c496b248dd, type: 2} + - {fileID: 11400000, guid: 4a3d021c6a1d2474cad4ea4e31dee9ef, type: 2} + - {fileID: 11400000, guid: 74814309f9845fb4cbcf8b25b1708df0, type: 2} m_DefaultRendererIndex: 0 m_RequireDepthTexture: 1 m_RequireOpaqueTexture: 1 @@ -65,6 +70,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 512 m_ReflectionProbeBlending: 0 m_ReflectionProbeBoxProjection: 0 + m_ReflectionProbeAtlas: 0 m_ShadowDistance: 56 m_ShadowCascadeCount: 4 m_Cascade2Split: 0.25 @@ -85,7 +91,6 @@ MonoBehaviour: m_MixedLightingSupported: 0 m_SupportsLightCookies: 0 m_SupportsLightLayers: 0 - m_DebugLevel: 0 m_StoreActionsOptimization: 0 m_UseAdaptivePerformance: 1 m_ColorGradingMode: 0 @@ -118,6 +123,8 @@ MonoBehaviour: m_PrefilteringModeForwardPlus: 0 m_PrefilteringModeDeferredRendering: 1 m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilteringModeScreenSpaceReflection: 1 + m_PrefilterWriteSmoothness: 1 m_PrefilterDebugKeywords: 1 m_PrefilterWriteRenderingLayers: 1 m_PrefilterHDROutput: 1 @@ -139,8 +146,14 @@ MonoBehaviour: m_PrefilterSoftShadowsQualityHigh: 0 m_PrefilterSoftShadows: 0 m_PrefilterScreenCoord: 0 + m_PrefilterScreenSpaceIrradiance: 0 m_PrefilterNativeRenderPass: 1 m_PrefilterUseLegacyLightmaps: 0 + m_PrefilterBicubicLightmapSampling: 0 + m_PrefilterReflectionProbeRotation: 0 + m_PrefilterReflectionProbeBlending: 0 + m_PrefilterReflectionProbeBoxProjection: 0 + m_PrefilterReflectionProbeAtlas: 0 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 3 m_Textures: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs new file mode 100644 index 00000000000..c732ef6e92a --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs @@ -0,0 +1,14 @@ +using UnityEngine; +using UnityEngine.Rendering.Universal; + +public class ResetAttachedCameraHistory : MonoBehaviour +{ + void Start() + { + if (TryGetComponent(out var data)) + { + // Reset Temporal-Antialiasing and other postprocess history for consistent test results. + data.resetHistory = true; + } + } +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs.meta new file mode 100644 index 00000000000..a20ff464022 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA/150_ResetHistory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8b8287334ffa2ff4eac7a4f9f967b039 \ No newline at end of file diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT.unity b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT.unity index 78f1286cdea..9779c293339 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT.unity +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f62b4a1adfd9d09a38f3a8ca9570094395f13d27665b5a330b6eda29824c467 -size 57768 +oid sha256:93f47e6ae76aa1e417e90b8adf8387ed96c22572d378ef3e30ea3b00cb3b80c6 +size 59787 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT_AlphaOutput.unity b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT_AlphaOutput.unity index 80fa66f8bf6..aa769f12ea2 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT_AlphaOutput.unity +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/150_TAA_RT_AlphaOutput.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14cc4fc65cd3db04a1646e0111910682a5749b547d657a65a28b7686061a3be7 -size 57768 +oid sha256:7fe60bf92dbf788d7626b8eb114f40aacab202d7acbdf81064772d904dfa9968 +size 59787 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO.meta new file mode 100644 index 00000000000..9bf2bbc96a3 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1234ecb486085384bba093c78bd98bbf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json new file mode 100644 index 00000000000..df06ef5210c --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.5, + 1.0, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 3.75, + 2.109375, + 1.0, + 1.0 + ], + "keywords": [ + "_BLUE_NOISE", + "_SAMPLE_COUNT_HIGH", + "_SOURCE_DEPTH_NORMALS" + ], + "aoMode": "Legacy", + "aoMethod": "BlueNoise", + "sampleCount": "High", + "depthSource": "DepthNormals", + "normalQuality": "High", + "blurQuality": "High", + "downsample": false, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json.meta new file mode 100644 index 00000000000..b1f5a035c30 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_High.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9962533b976bb47488aa1e304d4a90dd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json new file mode 100644 index 00000000000..efe0b0cd8df --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.5, + 0.5, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 3.75, + 2.109375, + 1.0, + 1.0 + ], + "keywords": [ + "_BLUE_NOISE", + "_SAMPLE_COUNT_MEDIUM", + "_SOURCE_DEPTH_NORMALS" + ], + "aoMode": "Legacy", + "aoMethod": "BlueNoise", + "sampleCount": "Medium", + "depthSource": "DepthNormals", + "normalQuality": "Medium", + "blurQuality": "Medium", + "downsample": true, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json.meta new file mode 100644 index 00000000000..eb9a8869f07 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_BN_Medium.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 718d4dfe0e674d541867d714702c2740 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json new file mode 100644 index 00000000000..cf688e1ecdf --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.0, + 1.0, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "keywords": [ + "_INTERLEAVED_GRADIENT", + "_SAMPLE_COUNT_HIGH", + "_SOURCE_DEPTH_NORMALS" + ], + "aoMode": "Legacy", + "aoMethod": "InterleavedGradient", + "sampleCount": "High", + "depthSource": "DepthNormals", + "normalQuality": "High", + "blurQuality": "High", + "downsample": false, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json.meta new file mode 100644 index 00000000000..9db1728f12d --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d60e7b952c63f9b4c975e6a0e44d279f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json new file mode 100644 index 00000000000..c3e5c248dd3 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.0, + 0.5, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "keywords": [ + "_INTERLEAVED_GRADIENT", + "_SAMPLE_COUNT_HIGH", + "_SOURCE_DEPTH_NORMALS" + ], + "aoMode": "Legacy", + "aoMethod": "InterleavedGradient", + "sampleCount": "High", + "depthSource": "DepthNormals", + "normalQuality": "High", + "blurQuality": "High", + "downsample": true, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json.meta new file mode 100644 index 00000000000..91395bdd629 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_High_Downsample.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7159d2b650053ee47a0e93ae03066bdd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json new file mode 100644 index 00000000000..337db9e4193 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.0, + 0.5, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "keywords": [ + "_INTERLEAVED_GRADIENT", + "_SAMPLE_COUNT_LOW", + "_SOURCE_DEPTH_LOW" + ], + "aoMode": "Legacy", + "aoMethod": "InterleavedGradient", + "sampleCount": "Low", + "depthSource": "Depth", + "normalQuality": "Low", + "blurQuality": "Low", + "downsample": true, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json.meta new file mode 100644 index 00000000000..905a1c2e9d0 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Low_DepthOnly.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7b0fda17fcb7562419e5b3d2edd1fd44 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json new file mode 100644 index 00000000000..a2c0c64051e --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json @@ -0,0 +1,118 @@ +{ + "width": 960, + "height": 540, + "ssaoParams": [ + 2.0, + 1.0, + 0.5, + 100.0 + ], + "ssaoParams2": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "aoDepthToViewParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "projectionParams2": [ + 3.3333332538604738, + 0.0, + 0.0, + 0.0 + ], + "sourceSize": [ + 960.0, + 540.0, + 0.0010416667209938169, + 0.0018518518190830947 + ], + "zBufferParams": [ + 3332.333251953125, + 1.0, + 3.3323333263397219, + 0.0010001659393310547 + ], + "depthTexelSize": [ + 0.0010416667209938169, + 0.0018518518190830947, + 960.0, + 540.0 + ], + "viewMatrix": [ + -1.0, 0.0, 0.0, 0.0, + 0.0, 0.9396926, 0.3420201, 0.0, + 0.0, -0.3420201, 0.9396927, 0.0, + 8.0, -11.95345, -25.63426, 1.0 + ], + "cameraViewProjection": [ + -0.974278569, + 0.0, + 0.0, + 0.0, + 0.0, + 1.62759531, + -0.342225373, + -0.3420201, + 0.0, + -0.5923962, + -0.9402567, + -0.9396927, + 7.79422855, + -20.7039833, + 25.0494671, + 25.63426 + ], + "cameraViewTopLeftCorner": [ + 0.3079202, + 0.06015352, + -0.341147453, + 0.0 + ], + "cameraViewXExtent": [ + -0.6158404, + 0.0, + 0.0, + 0.0 + ], + "cameraViewYExtent": [ + 0.0, + -0.325519145, + 0.118479267, + 0.0 + ], + "cameraViewZExtent": [ + 0.0, + -341.922668, + -939.4248, + 0.0 + ], + "blueNoiseParams": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "keywords": [ + "_INTERLEAVED_GRADIENT", + "_SAMPLE_COUNT_MEDIUM", + "_SOURCE_DEPTH_NORMALS" + ], + "aoMode": "Legacy", + "aoMethod": "InterleavedGradient", + "sampleCount": "Medium", + "depthSource": "DepthNormals", + "normalQuality": "Medium", + "blurQuality": "Medium", + "downsample": true, + "intensity": 2.0, + "radius": 1.0, + "falloff": 100.0, + "isComputeShader": false, + "directionCount": 0, + "stepCount": 0 +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json.meta new file mode 100644 index 00000000000..f7bdb5cc720 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/Legacy_IGN_Medium.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2695e04433fb4d04d9078542114162a8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset new file mode 100644 index 00000000000..4a44db88731 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: SSAO_BN_High + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: + - {fileID: 833040173654816463} + m_RendererFeatureMap: cf3653d29f8d8f0b + xrSystemData: {fileID: 0} + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 3 + m_PrepassLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 1 + m_DepthAttachmentFormat: 0 + m_DepthTextureFormat: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 + m_TileOnlyMode: 0 +--- !u!114 &833040173654816463 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceAmbientOcclusion + m_Active: 1 + m_Settings: + AOMethod: 0 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 3 + DirectLightingStrength: 0.25 + Radius: 0.035 + Samples: 0 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset.meta new file mode 100644 index 00000000000..9130146bec0 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_High.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 597b9f1a0b1557c448178217c078d942 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset new file mode 100644 index 00000000000..4254f9288e8 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-6062531928060741623 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceAmbientOcclusion + m_Active: 1 + m_Settings: + AOMethod: 0 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 3 + DirectLightingStrength: 0.25 + Radius: 0.035 + Samples: 1 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: SSAO_BN_Medium + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: + - {fileID: -6062531928060741623} + m_RendererFeatureMap: 09b87904558fddab + xrSystemData: {fileID: 0} + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 3 + m_PrepassLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 1 + m_DepthAttachmentFormat: 0 + m_DepthTextureFormat: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 + m_TileOnlyMode: 0 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset.meta new file mode 100644 index 00000000000..27b4814c33b --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_BN_Medium.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd2ef63e3ab2d8040b42e100d9ecd08b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset new file mode 100644 index 00000000000..aaec996cde5 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-3177345659720476864 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceAmbientOcclusion + m_Active: 1 + m_Settings: + AOMethod: 1 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 3 + DirectLightingStrength: 0.25 + Radius: 0.035 + Samples: 0 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: SSAO_IGN_High + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: + - {fileID: -3177345659720476864} + m_RendererFeatureMap: 4057bbeff4cce7d3 + xrSystemData: {fileID: 0} + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 3 + m_PrepassLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 1 + m_DepthAttachmentFormat: 0 + m_DepthTextureFormat: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 + m_TileOnlyMode: 0 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset.meta new file mode 100644 index 00000000000..7e86b519471 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_High.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c7f4485aa22e9c4e984f7c496b248dd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset new file mode 100644 index 00000000000..e043dde9d2f --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: SSAO_IGN_Low_DepthOnly + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: + - {fileID: 1657303663721221233} + m_RendererFeatureMap: 718c0ec1e6ecff16 + xrSystemData: {fileID: 0} + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 3 + m_PrepassLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 1 + m_DepthAttachmentFormat: 0 + m_DepthTextureFormat: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 + m_TileOnlyMode: 0 +--- !u!114 &1657303663721221233 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceAmbientOcclusion + m_Active: 1 + m_Settings: + AOMethod: 1 + Downsample: 0 + AfterOpaque: 0 + Source: 0 + NormalSamples: 1 + Intensity: 3 + DirectLightingStrength: 0.25 + Radius: 0.035 + Samples: 2 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset.meta new file mode 100644 index 00000000000..56517228866 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Low_DepthOnly.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74814309f9845fb4cbcf8b25b1708df0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset new file mode 100644 index 00000000000..1da16203616 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset @@ -0,0 +1,83 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: SSAO_IGN_Medium + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: + - {fileID: 48130123168883833} + m_RendererFeatureMap: 79247a8e17feaa00 + xrSystemData: {fileID: 0} + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 3 + m_PrepassLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 1 + m_DepthAttachmentFormat: 0 + m_DepthTextureFormat: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 + m_TileOnlyMode: 0 +--- !u!114 &48130123168883833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceAmbientOcclusion + m_Active: 1 + m_Settings: + AOMethod: 1 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 3 + DirectLightingStrength: 0.25 + Radius: 0.035 + Samples: 1 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset.meta new file mode 100644 index 00000000000..a12cf97934f --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/SSAO_IGN_Medium.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a3d021c6a1d2474cad4ea4e31dee9ef +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png new file mode 100644 index 00000000000..8ac3a6450fd --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcb67b83ad8ca431461399bb1c2af9175b2825b0b5a6a0f101c28da28ecc894a +size 101448 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png.meta new file mode 100644 index 00000000000..e97d4926405 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/bluenoise.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: e8eecf064c0dd07409dd5c04f808f381 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + 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: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + 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: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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 + 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/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr new file mode 100644 index 00000000000..2cb6f641e4a --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55f824ec2b9e34dd0df5add2faae18621dfd8b02ee72e78a010d2aa8c66cc66b +size 8303371 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr.meta new file mode 100644 index 00000000000..dfc860684da --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/depth.exr.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 45def715dab84484383ad99625e6a7a5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + 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: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + 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: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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 + 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/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png new file mode 100644 index 00000000000..3229114430a --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfbb88e3b2e77483f7cebd122b514efdfbdaac4b55b1e899892d3405db41a1f5 +size 1227645 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png.meta new file mode 100644 index 00000000000..7eabde67196 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_PostPro/Assets/Scenes/500_SSAO/normals.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: e0142770f3097e64a929ea7d9aa06b2e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + 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: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + 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: 0 + 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: Switch + 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: From 671d2da41e1d253ea93b9e3bcf8c2ddd8e7c72b8 Mon Sep 17 00:00:00 2001 From: Layla Arab Date: Thu, 23 Apr 2026 22:20:28 +0000 Subject: [PATCH 45/56] Add option for transparent materials to choose whether to contribute to SSR --- .../Editor/ShaderGUI/Shaders/LitShader.cs | 8 +++++ .../Shaders/ParticlesSimpleLitShader.cs | 2 +- .../ShaderGUI/Shaders/SimpleLitShader.cs | 2 +- .../Editor/ShaderGUI/ShadingModels/LitGUI.cs | 17 +++++++++- .../ShaderGUI/ShadingModels/SimpleLitGUI.cs | 31 +++++++++++++++++-- .../Shaders/ComplexLit.shader | 2 ++ .../Shaders/Lit.shader | 2 ++ .../Shaders/LitDepthNormalsPass.hlsl | 5 +++ .../Shaders/SimpleLit.shader | 3 ++ .../Shaders/SimpleLitDepthNormalsPass.hlsl | 5 +++ 10 files changed, 72 insertions(+), 5 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/LitShader.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/LitShader.cs index bb3b55c0ba9..d0fac20f1a0 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/LitShader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/LitShader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Rendering; namespace UnityEditor.Rendering.Universal.ShaderGUI { @@ -63,6 +64,13 @@ public override void DrawAdvancedOptions(Material material) #if URP_SCREEN_SPACE_REFLECTION if (litProperties.screenSpaceReflections != null) materialEditor.ShaderProperty(litProperties.screenSpaceReflections, LitGUI.Styles.screenSpaceReflectionsText); + + if (litProperties.screenSpaceReflectionsContributeTransparent != null) + { + bool isTransparent = material.renderQueue >= (int)RenderQueue.Transparent; + if (isTransparent) + materialEditor.ShaderProperty(litProperties.screenSpaceReflectionsContributeTransparent, LitGUI.Styles.screenSpaceReflectionsContributeTransparentText); + } #endif base.DrawAdvancedOptions(material); diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/ParticlesSimpleLitShader.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/ParticlesSimpleLitShader.cs index fcaae57fbd2..28299ec6eb3 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/ParticlesSimpleLitShader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/ParticlesSimpleLitShader.cs @@ -40,7 +40,7 @@ public override void DrawSurfaceInputs(Material material) public override void DrawAdvancedOptions(Material material) { - SimpleLitGUI.Advanced(shadingModelProperties); + SimpleLitGUI.Advanced(shadingModelProperties, materialEditor, material); materialEditor.ShaderProperty(particleProps.flipbookMode, ParticleGUI.Styles.flipbookMode); ParticleGUI.FadingOptions(material, materialEditor, particleProps); diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/SimpleLitShader.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/SimpleLitShader.cs index b0db40233d2..4bbf57bf2d8 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/SimpleLitShader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/Shaders/SimpleLitShader.cs @@ -44,7 +44,7 @@ public override void DrawSurfaceInputs(Material material) public override void DrawAdvancedOptions(Material material) { - SimpleLitGUI.Advanced(shadingModelProperties); + SimpleLitGUI.Advanced(shadingModelProperties, materialEditor, material); base.DrawAdvancedOptions(material); } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/LitGUI.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/LitGUI.cs index 2a1c8f73405..b388728ac24 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/LitGUI.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/LitGUI.cs @@ -96,6 +96,13 @@ public static class Styles public static GUIContent screenSpaceReflectionsText = EditorGUIUtility.TrTextContent("Screen Space Reflections", "When enabled, the Material samples screen space reflections."); + + /// + /// The text and tooltip for the screen space reflections contribute transparent GUI. + /// + public static GUIContent screenSpaceReflectionsContributeTransparentText = + EditorGUIUtility.TrTextContent("Contribute Screen Space Reflections", + "When enabled, this Material will contribute to screen space reflections. This will include the object in the transparency-depth prepass."); #endif /// @@ -236,6 +243,11 @@ public struct LitProperties /// The MaterialProperty for screen space reflections. /// public MaterialProperty screenSpaceReflections; + + /// + /// The MaterialProperty for screen space reflections contribute transparent. + /// + public MaterialProperty screenSpaceReflectionsContributeTransparent; #endif /// @@ -284,8 +296,8 @@ public LitProperties(MaterialProperty[] properties) reflections = BaseShaderGUI.FindProperty("_EnvironmentReflections", properties, false); #if URP_SCREEN_SPACE_REFLECTION screenSpaceReflections = BaseShaderGUI.FindProperty("_ScreenSpaceReflections", properties, false); + screenSpaceReflectionsContributeTransparent = BaseShaderGUI.FindProperty("_ScreenSpaceReflectionsContributeTransparent", properties, false); #endif - clearCoat = BaseShaderGUI.FindProperty("_ClearCoat", properties, false); clearCoatMap = BaseShaderGUI.FindProperty("_ClearCoatMap", properties, false); clearCoatMask = BaseShaderGUI.FindProperty("_ClearCoatMask", properties, false); @@ -493,6 +505,9 @@ public static void SetMaterialKeywords(Material material) if (material.HasProperty("_ScreenSpaceReflections")) CoreUtils.SetKeyword(material, "_SCREENSPACEREFLECTIONS_OFF", material.GetFloat("_ScreenSpaceReflections") == 0.0f); + if (material.HasProperty("_ScreenSpaceReflectionsContributeTransparent")) + CoreUtils.SetKeyword(material, "_SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF", + material.GetFloat("_ScreenSpaceReflectionsContributeTransparent") == 0.0f && material.renderQueue >= (int)UnityEngine.Rendering.RenderQueue.Transparent); #endif if (material.HasProperty("_OcclusionMap")) CoreUtils.SetKeyword(material, "_OCCLUSIONMAP", material.GetTexture("_OcclusionMap")); diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/SimpleLitGUI.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/SimpleLitGUI.cs index c649d3d5feb..4d533eefcee 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/SimpleLitGUI.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGUI/ShadingModels/SimpleLitGUI.cs @@ -91,6 +91,13 @@ public struct SimpleLitProperties /// public MaterialProperty bumpMapProp; +#if URP_SCREEN_SPACE_REFLECTION + /// + /// The MaterialProperty for screen space reflections contribute transparent. + /// + public MaterialProperty screenSpaceReflectionsContributeTransparent; +#endif + /// /// Constructor for the SimpleLitProperties container struct. /// @@ -104,6 +111,9 @@ public SimpleLitProperties(MaterialProperty[] properties) smoothnessMapChannel = BaseShaderGUI.FindProperty("_SmoothnessSource", properties, false); smoothness = BaseShaderGUI.FindProperty("_Smoothness", properties, false); bumpMapProp = BaseShaderGUI.FindProperty("_BumpMap", properties, false); +#if URP_SCREEN_SPACE_REFLECTION + screenSpaceReflectionsContributeTransparent = BaseShaderGUI.FindProperty("_ScreenSpaceReflectionsContributeTransparent", properties, false); +#endif } } @@ -122,8 +132,10 @@ public static void Inputs(SimpleLitProperties properties, MaterialEditor materia /// /// Draws the advanced GUI. /// - /// - public static void Advanced(SimpleLitProperties properties) + /// The SimpleLit properties. + /// The material editor. + /// The material to use. + public static void Advanced(SimpleLitProperties properties, MaterialEditor materialEditor, Material material) { SpecularSource specularSource = (SpecularSource)properties.specHighlights.floatValue; EditorGUI.BeginChangeCheck(); @@ -132,6 +144,15 @@ public static void Advanced(SimpleLitProperties properties) if (EditorGUI.EndChangeCheck()) properties.specHighlights.floatValue = enabled ? (float)SpecularSource.SpecularTextureAndColor : (float)SpecularSource.NoSpecular; EditorGUI.showMixedValue = false; + +#if URP_SCREEN_SPACE_REFLECTION + if (properties.screenSpaceReflectionsContributeTransparent != null) + { + bool isTransparent = material.renderQueue >= (int)UnityEngine.Rendering.RenderQueue.Transparent; + if (isTransparent) + materialEditor.ShaderProperty(properties.screenSpaceReflectionsContributeTransparent, LitGUI.Styles.screenSpaceReflectionsContributeTransparentText); + } +#endif } /// @@ -156,6 +177,12 @@ public static void DoSpecularArea(SimpleLitProperties properties, MaterialEditor public static void SetMaterialKeywords(Material material) { UpdateMaterialSpecularSource(material); + +#if URP_SCREEN_SPACE_REFLECTION + if (material.HasProperty("_ScreenSpaceReflectionsContributeTransparent")) + CoreUtils.SetKeyword(material, "_SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF", + material.GetFloat("_ScreenSpaceReflectionsContributeTransparent") == 0.0f && material.renderQueue >= (int)UnityEngine.Rendering.RenderQueue.Transparent); +#endif } private static void UpdateMaterialSpecularSource(Material material) diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/ComplexLit.shader b/Packages/com.unity.render-pipelines.universal/Shaders/ComplexLit.shader index bfbbc2fb189..855c5541fcb 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/ComplexLit.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/ComplexLit.shader @@ -25,6 +25,7 @@ Shader "Universal Render Pipeline/Complex Lit" [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 [ToggleOff] _ScreenSpaceReflections("Screen Space Reflections", Float) = 1.0 + [ToggleOff] _ScreenSpaceReflectionsContributeTransparent("Screen Space Reflections Contribute Transparent", Float) = 1.0 _BumpScale("Scale", Float) = 1.0 _BumpMap("Normal Map", 2D) = "bump" {} @@ -407,6 +408,7 @@ Shader "Universal Render Pipeline/Complex Lit" #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP #pragma shader_feature_local_fragment _SCREENSPACEREFLECTIONS_OFF + #pragma shader_feature_local_fragment _SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF // ------------------------------------- // Universal Pipeline keywords diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Lit.shader b/Packages/com.unity.render-pipelines.universal/Shaders/Lit.shader index 42a1cc2031a..bb043b49228 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Lit.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Lit.shader @@ -22,6 +22,7 @@ Shader "Universal Render Pipeline/Lit" [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 [ToggleOff] _ScreenSpaceReflections("Screen Space Reflections", Float) = 1.0 + [ToggleOff] _ScreenSpaceReflectionsContributeTransparent("Screen Space Reflections Contribute Transparent", Float) = 1.0 _BumpScale("Scale", Float) = 1.0 _BumpMap("Normal Map", 2D) = "bump" {} @@ -405,6 +406,7 @@ Shader "Universal Render Pipeline/Lit" #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP #pragma shader_feature_local_fragment _SCREENSPACEREFLECTIONS_OFF + #pragma shader_feature_local_fragment _SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF // ------------------------------------- // Unity defined keywords diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl index 25ecaf04e2c..66470c7cb18 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl @@ -120,6 +120,11 @@ void DepthNormalsFragment( LODFadeCrossFade(input.positionCS); #endif + #if _SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF_KEYWORD_DECLARED + if (_SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF) + discard; + #endif + #if defined(_GBUFFER_NORMALS_OCT) float3 normalWS = normalize(input.normalWS); float2 octNormalWS = PackNormalOctQuadEncode(normalWS); // values between [-1, +1], must use fp32 on some platforms diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLit.shader b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLit.shader index 622cc282052..5bc98c9cdd2 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLit.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLit.shader @@ -15,6 +15,8 @@ Shader "Universal Render Pipeline/Simple Lit" _SmoothnessSource("Smoothness Source", Float) = 0.0 _SpecularHighlights("Specular Highlights", Float) = 1.0 + [ToggleOff] _ScreenSpaceReflectionsContributeTransparent("Screen Space Reflections Contribute Transparent", Float) = 1.0 + [HideInInspector] _BumpScale("Scale", Float) = 1.0 [NoScaleOffset] _BumpMap("Normal Map", 2D) = "bump" {} @@ -352,6 +354,7 @@ Shader "Universal Render Pipeline/Simple Lit" #pragma shader_feature_local _NORMALMAP #pragma shader_feature_local _ALPHATEST_ON #pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA + #pragma shader_feature_local_fragment _SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF // ------------------------------------- // Unity defined keywords diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl index d336ccc27fd..089ec5b98e0 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl @@ -87,6 +87,11 @@ void DepthNormalsFragment( LODFadeCrossFade(input.positionCS); #endif + #if _SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF_KEYWORD_DECLARED + if (_SCREENSPACEREFLECTIONSCONTRIBUTETRANSPARENT_OFF) + discard; + #endif + #if defined(_GBUFFER_NORMALS_OCT) float3 normalWS = normalize(input.normalWS); float2 octNormalWS = PackNormalOctQuadEncode(normalWS); // values between [-1, +1], must use fp32 on some platforms From 0fb5779effb8f717a63568288daf803e71d9ed8c Mon Sep 17 00:00:00 2001 From: Wind Xu Date: Thu, 23 Apr 2026 22:20:28 +0000 Subject: [PATCH 46/56] Bump Cinemachine to V3 in manifest --- .../Projects/UniversalGraphicsTest_2D/Packages/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Packages/manifest.json b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Packages/manifest.json index 09e6e7b63c0..a1ab3f5ed29 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Packages/manifest.json +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Packages/manifest.json @@ -4,7 +4,7 @@ "dependencies": { "com.unity.2d.sprite": "1.0.0", "com.unity.2d.tilemap": "1.0.0", - "com.unity.cinemachine": "2.10.7", + "com.unity.cinemachine": "3.1.6", "com.unity.ext.nunit": "1.0.0", "com.unity.external.test-protocol": "2.0.0-exp.2", "com.unity.feature.2d": "file:../../../../../Packages/com.unity.feature.2d", From 0ff666ff21f7ae1d314b50ff91d988850234d279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20V=C3=A1zquez=20Mart=C3=ADnez?= Date: Thu, 23 Apr 2026 22:20:34 +0000 Subject: [PATCH 47/56] [Rendering Debugger]Fixes for Foldouts --- .../Editor/Debugging/DebugWindow.uss | 68 +++++++++++++------ .../Runtime/Debugging/DebugUI.Containers.cs | 4 +- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uss b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uss index 4574a8b9a73..722620e53b8 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uss +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.uss @@ -63,15 +63,41 @@ /* Header Foldout */ -.debug-window-foldout > .unity-foldout__toggle { - border-width: 1px 0px 1px 0px; +.debug-window-foldout-header > .unity-foldout__toggle { + padding-top: 1px !important; + padding-bottom: 1px !important; margin-top: 0px !important; margin-bottom: 0px !important; + margin-left: -2px; + margin-right: -4px; + border-top-width: 1px; border-top-color: var(--unity-colors-default-border); - border-bottom-color: var(--unity-colors-inspector_titlebar-border_accent); + border-bottom-width: 1px; + border-bottom-color: var(--unity-colors-default-border); background-color: var(--unity-colors-inspector_titlebar-background); } +.debug-window-foldout-header > .unity-foldout__toggle:hover { + background-color: var(--unity-colors-inspector_titlebar-background-hover); +} + +.debug-window-foldout-header > .unity-foldout__toggle > .unity-toggle__input > .unity-toggle__checkmark +{ + margin-left: 4px; + margin-right: 4px; +} + +.debug-window-foldout-header .unity-foldout__text { + -unity-font-style: bold; +} + +.debug-window-foldout > .unity-foldout__toggle { + padding-top: 1px !important; + padding-bottom: 1px !important; + margin-top: 0px !important; + margin-bottom: 0px !important; +} + .debug-window-foldout > .unity-foldout__toggle:hover { background-color: var(--unity-colors-inspector_titlebar-background-hover); } @@ -82,33 +108,35 @@ margin-right: 4px; } -.more-options-button { - background-image: var(--unity-icons-pane_options); - background-size: contain; - background-repeat: no-repeat; - background-color: transparent; - border-color: transparent; - width: 16px; - margin: 0px 4px 0px 0px !important; - padding: 0px 0px 0px 0px !important; +.debug-window-foldout .unity-foldout__text { + -unity-font-style: bold; } -.more-options-button:hover { - background-color: var(--unity-colors-button-background-hover); +.more-options-button { + background-image: var(--unity-icons-pane_options); } -.info-button { +.info-button, +.more-options-button { background-color: transparent; - border-color: transparent; - width: 24px; - margin: 0px 4px 0px 0px !important; - padding: 0px 0px 0px 0px !important; + margin: 2px 2px 1px 3px; + padding: 0px 2px 0px 0px; + border-width: 0px; + border-radius: 2px 2px 2px 2px; + width: 20px; + height: 20px; } -.info-button:hover { +.info-button:hover, +.more-options-button:hover{ background-color: var(--unity-colors-button-background-hover); } +.info-button:disabled +.info-button:disabled, +.more-options-button:disabled { +} + #debug-window-no-results-label { display: none; -unity-text-align: middle-center; 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 9120f02952c..be00eaeba19 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 @@ -246,7 +246,9 @@ protected override VisualElement Create() } // Add special classes for styles - container.AddToClassList("debug-window-foldout"); + // Use header style for top-level foldouts (not inside a Container), regular style for nested ones + bool isHeaderFoldout = parent is DebugUI.Panel; + container.AddToClassList(isHeaderFoldout ? "debug-window-foldout-header" : "debug-window-foldout"); container.Q(className: "unity-foldout__text").AddToClassList("debug-window-search-filter-target"); // Update UI to match object's initial state From 74235685f5db81d95b6b340dfbce3d2e5c9cd080 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Thu, 23 Apr 2026 22:20:36 +0000 Subject: [PATCH 48/56] Re-enable RuntimeProfilerTests --- .../Tests/Runtime/DebugFrameTimingTests.cs | 172 ++++++++++++++++++ .../Runtime/DebugFrameTimingTests.cs.meta | 2 + .../Tests/Runtime/RuntimeProfilerTests.cs | 55 ++++-- 3 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs new file mode 100644 index 00000000000..6545bf09082 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs @@ -0,0 +1,172 @@ +using NUnit.Framework; + +namespace UnityEngine.Rendering.Tests +{ + static class FrameTimingTestExtensions + { + public static BottleneckHistogram ToHistogram(this FrameTimeSample s) + { + var history = new BottleneckHistory(1); + history.AddBottleneckFromAveragedSample(s); + history.ComputeHistogram(); + return history.Histogram; + } + + public static string ToDebugString(this BottleneckHistogram h) => + $"GPU={h.GPU}, CPU={h.CPU}, PresentLimited={h.PresentLimited}, Balanced={h.Balanced}"; + } + + class DebugFrameTimingTests + { + static FrameTimeSample MakeSample( + float fullFrameTime, + float gpu, + float mainCpu, + float renderCpu, + float presentWait = 0f, + float fps = 0f) + { + return new FrameTimeSample + { + FullFrameTime = fullFrameTime, + GPUFrameTime = gpu, + MainThreadCPUFrameTime = mainCpu, + RenderThreadCPUFrameTime = renderCpu, + MainThreadCPUPresentWaitTime = presentWait, + FramesPerSecond = fps + }; + } + + [Test] + public void Histogram_ZeroGPUFrameTime_ProducesIndeterminate() + { + var h = MakeSample(fullFrameTime: 10, gpu: 0, mainCpu: 5, renderCpu: 5).ToHistogram(); + Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f), + $"Zero GPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_ZeroMainThreadCPUFrameTime_ProducesIndeterminate() + { + var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 0, renderCpu: 5).ToHistogram(); + Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f), + $"Zero MainThreadCPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_GPUBound_ProducesGPU() + { + // GPU close to FullFrameTime, CPU times are not. + var h = MakeSample(fullFrameTime: 10, gpu: 9, mainCpu: 2, renderCpu: 2).ToHistogram(); + Assert.That(h.GPU, Is.EqualTo(1f), + $"GPU-dominant sample must put 100% in the GPU bucket. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_MainThreadCPUBound_ProducesCPU() + { + var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 9, renderCpu: 2).ToHistogram(); + Assert.That(h.CPU, Is.EqualTo(1f), + $"MainThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_RenderThreadCPUBound_ProducesCPU() + { + var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 9).ToHistogram(); + Assert.That(h.CPU, Is.EqualTo(1f), + $"RenderThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_BalancedWithPresentWait_ProducesPresentLimited() + { + var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 2, presentWait: 1f).ToHistogram(); + Assert.That(h.PresentLimited, Is.EqualTo(1f), + $"Non-dominant sample with present wait > 0.5ms must classify as PresentLimited. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_BalancedWithoutPresentWait_ProducesBalanced() + { + var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 5, renderCpu: 5, presentWait: 0f).ToHistogram(); + Assert.That(h.Balanced, Is.EqualTo(1f), + $"Non-dominant sample with no present wait must classify as Balanced. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_MixedSamples_RatiosMatchSampleCounts() + { + // 2x GPU, 2x CPU, 1x PresentLimited -> 0.4 / 0.4 / 0.2 / 0 + var history = new BottleneckHistory(8); + history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2)); + history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2)); + history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2)); + history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2)); + history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 2, 2, presentWait: 1f)); + history.ComputeHistogram(); + var h = history.Histogram; + + Assert.That(h.GPU, Is.EqualTo(0.4f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}."); + Assert.That(h.CPU, Is.EqualTo(0.4f).Within(1e-6f), $"CPU bucket. Got {h.ToDebugString()}."); + Assert.That(h.PresentLimited, Is.EqualTo(0.2f).Within(1e-6f), $"PresentLimited bucket. Got {h.ToDebugString()}."); + Assert.That(h.Balanced, Is.EqualTo(0f), $"Balanced bucket. Got {h.ToDebugString()}."); + } + + [Test] + public void Histogram_IndeterminateSamples_ReduceVisibleTotalBelowOne() + { + // 1 valid GPU sample + 4 indeterminate (GPU=0) -> visible total = 0.2. + var history = new BottleneckHistory(8); + history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2)); + for (int i = 0; i < 4; i++) + history.AddBottleneckFromAveragedSample(MakeSample(10, 0, 5, 5)); + history.ComputeHistogram(); + var h = history.Histogram; + + Assert.That(h.GPU, Is.EqualTo(0.2f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}."); + Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0.2f).Within(1e-6f), + $"Indeterminate samples must be excluded from visible buckets. Got {h.ToDebugString()}."); + } + + [Test] + public void BottleneckHistory_DiscardOldSamples_KeepsAtMostHistorySize() + { + // With historySize=3, add 5 GPU-bound then 2 CPU-bound samples. + // Retained samples should be [GPU, CPU, CPU] -> GPU=1/3, CPU=2/3. + const int historySize = 3; + var history = new BottleneckHistory(historySize); + var gpuSample = MakeSample(10, 9, 2, 2); + var cpuSample = MakeSample(10, 2, 9, 2); + + for (int i = 0; i < 5; i++) + { + history.DiscardOldSamples(historySize); + history.AddBottleneckFromAveragedSample(gpuSample); + } + for (int i = 0; i < 2; i++) + { + history.DiscardOldSamples(historySize); + history.AddBottleneckFromAveragedSample(cpuSample); + } + history.ComputeHistogram(); + var h = history.Histogram; + + Assert.That(h.GPU, Is.EqualTo(1f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}."); + Assert.That(h.CPU, Is.EqualTo(2f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}."); + } + + [Test] + public void Reset_ClearsBottleneckHistogram() + { + var debug = new DebugFrameTiming(); + debug.m_BottleneckHistory.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2)); + debug.m_BottleneckHistory.ComputeHistogram(); + + debug.Reset(); + + var h = debug.m_BottleneckHistory.Histogram; + Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f), $"Reset must zero the histogram. Got {h.ToDebugString()}."); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs.meta new file mode 100644 index 00000000000..d323b5d4261 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3db890d1d31f2e8469e35a12ff97e3fe \ No newline at end of file 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 15d093325f1..bbff9866174 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs @@ -1,6 +1,9 @@ using System.Collections; using UnityEngine.TestTools; using NUnit.Framework; +#if ENABLE_VR && ENABLE_XR_MODULE +using UnityEngine.XR; +#endif namespace UnityEngine.Rendering.Tests { @@ -21,6 +24,9 @@ public void Setup() if (Application.isBatchMode) Assert.Ignore("Frame timing tests are not supported in batch mode, skipping test."); + if (GraphicsSettings.currentRenderPipeline == null) + Assert.Ignore("No active Render Pipeline is set, skipping test."); + // HACK #1 - really shouldn't have to do this here, but previous tests are leaking gameobjects #pragma warning disable CS0618 // Type or member is obsolete var objects = GameObject.FindObjectsByType(FindObjectsSortMode.InstanceID); @@ -51,21 +57,23 @@ protected IEnumerator Warmup() } } - // 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 - [UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android, RuntimePlatform.Switch, RuntimePlatform.WindowsEditor })] // Unstable on WindowsEditor: https://jira.unity3d.com/browse/UUM-135231 class RuntimeProfilerTests : RuntimeProfilerTestBase { [UnityTest] public IEnumerator RuntimeProfilerGivesNonZeroOutput() { - if ((Application.platform == RuntimePlatform.LinuxPlayer || - Application.platform == RuntimePlatform.LinuxEditor) - && SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore) - { - Assert.Ignore("Test is failing on Linux OpenGLCore. https://jira.unity3d.com/browse/GFXFOUND-559"); - } + // GPU Frame Time support is partial (https://docs.unity3d.com/6000.6/Documentation/Manual/frame-timing-manager.html), + // so adding exceptions here. + bool supportsGpuFrameTime = true; + + if ((Application.platform == RuntimePlatform.LinuxPlayer || Application.platform == RuntimePlatform.LinuxEditor) && SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore) + supportsGpuFrameTime = false; // Linux + OpenGLCore + if (Application.platform == RuntimePlatform.WebGLPlayer) + supportsGpuFrameTime = false; // WebGL/WebGPU +#if ENABLE_VR && ENABLE_XR_MODULE + if (XRSettings.enabled) + supportsGpuFrameTime = false; // XR +#endif yield return Warmup(); @@ -86,11 +94,28 @@ public IEnumerator RuntimeProfilerGivesNonZeroOutput() yield return null; } - Assert.True( - m_DebugFrameTiming.m_BottleneckHistory.Histogram.Balanced > 0 || - m_DebugFrameTiming.m_BottleneckHistory.Histogram.CPU > 0 || - m_DebugFrameTiming.m_BottleneckHistory.Histogram.GPU > 0 || - m_DebugFrameTiming.m_BottleneckHistory.Histogram.PresentLimited > 0); + // After k_NumFramesToRender frames, we should have a valid average for every headline counter. + // A failure means the counter was zero on every captured frame. RenderThreadCPUFrameTime and + // MainThreadCPUPresentWaitTime are excluded because they can legitimately be zero (modes without + // a separate render thread; no vsync / no frame rate cap). GPUFrameTime is only asserted on + // platforms known to report it (see supportsGpuFrameTime above). + var avg = m_DebugFrameTiming.m_FrameHistory.SampleAverage; + var zeroAvg = new System.Collections.Generic.List(); + if (avg.FramesPerSecond <= 0f) + zeroAvg.Add(nameof(avg.FramesPerSecond)); + if (avg.FullFrameTime <= 0f) + zeroAvg.Add(nameof(avg.FullFrameTime)); + if (avg.MainThreadCPUFrameTime <= 0f) + zeroAvg.Add(nameof(avg.MainThreadCPUFrameTime)); + if (supportsGpuFrameTime && avg.GPUFrameTime <= 0f) + zeroAvg.Add(nameof(avg.GPUFrameTime)); + + Assert.That(zeroAvg, Is.Empty, + $"After {k_NumFramesToRender} frames the following SampleAverage counters were zero: [{string.Join(", ", zeroAvg)}]. " + + $"All averages: FramesPerSecond={avg.FramesPerSecond}, FullFrameTime={avg.FullFrameTime}, " + + $"MainThreadCPUFrameTime={avg.MainThreadCPUFrameTime}, RenderThreadCPUFrameTime={avg.RenderThreadCPUFrameTime}, " + + $"GPUFrameTime={avg.GPUFrameTime} (asserted={supportsGpuFrameTime}), " + + $"MainThreadCPUPresentWaitTime={avg.MainThreadCPUPresentWaitTime}."); } } } From 155676a92071628d3999505c536b9765bb34f071 Mon Sep 17 00:00:00 2001 From: Ludovic Theobald Date: Thu, 23 Apr 2026 22:20:37 +0000 Subject: [PATCH 49/56] [VFX] Profiling window / panels fixes --- .../GraphView/Profiling/VFXProfilingBoard.cs | 2 +- .../Profiling/VFXSystemProfilerUI.cs | 20 +++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXProfilingBoard.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXProfilingBoard.cs index d90751aafee..ecd6fd530a5 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXProfilingBoard.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXProfilingBoard.cs @@ -394,7 +394,7 @@ private void CreateOrResumeUpdateItems() void Update() { - if (m_AttachedComponent == null) + if (m_AttachedComponent == null || m_AttachedComponent.visualEffectAsset == null) { Detach(); return; diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXSystemProfilerUI.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXSystemProfilerUI.cs index e18c51c8a82..b56df690c05 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXSystemProfilerUI.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Profiling/VFXSystemProfilerUI.cs @@ -13,7 +13,11 @@ public VFXSystemProfilerUI(VFXContextUI initContextUI, List((e, contextPanel) => + { + contextPanel.SetVerticalOffset(e.newRect.height); + contextPanel.RepositionPanel(); + }, m_SystemContexts[0]); VFXSystemNames systemNames = controller.viewController.graph.systemNames; string systemName = systemNames.GetUniqueSystemName(controller.model.GetData()); @@ -70,20 +74,6 @@ public string GetSystemName() return m_SystemName; } - void ScheduleRepositionInitializePanel() - { - schedule.Execute(() => - { - m_SystemContexts[0].SetVerticalOffset(resolvedStyle.height); - m_SystemContexts[0].RepositionPanel(); - }); - } - protected override void OnCollapseChanged(ChangeEvent evt) - { - base.OnCollapseChanged(evt); - ScheduleRepositionInitializePanel(); - } - void AddStatusSection() { VisualElement statusContainer = new VisualElement From de1c7769f3fe2f32404dc8b751a3b773ef81bcb4 Mon Sep 17 00:00:00 2001 From: April Roszkowski Date: Thu, 23 Apr 2026 22:20:45 +0000 Subject: [PATCH 50/56] [UUM-137272] Change file access strategy in Shader Graph importer --- .../Editor/Importers/ShaderGraphImporter.cs | 2 +- .../Editor/Util/FileUtilities.cs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.shadergraph/Editor/Importers/ShaderGraphImporter.cs b/Packages/com.unity.shadergraph/Editor/Importers/ShaderGraphImporter.cs index 249bfe118ce..8d60385ade5 100644 --- a/Packages/com.unity.shadergraph/Editor/Importers/ShaderGraphImporter.cs +++ b/Packages/com.unity.shadergraph/Editor/Importers/ShaderGraphImporter.cs @@ -235,7 +235,7 @@ public override void OnImportAsset(AssetImportContext ctx) AssetCollection assetCollection = new AssetCollection(); MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection); - var textGraph = File.ReadAllText(path, Encoding.UTF8); + var textGraph = FileUtilities.ReadAllTextUTF8(assetPath); var graph = new GraphData { messageManager = new MessageManager(), diff --git a/Packages/com.unity.shadergraph/Editor/Util/FileUtilities.cs b/Packages/com.unity.shadergraph/Editor/Util/FileUtilities.cs index ffc52fe5bb8..32932deb711 100644 --- a/Packages/com.unity.shadergraph/Editor/Util/FileUtilities.cs +++ b/Packages/com.unity.shadergraph/Editor/Util/FileUtilities.cs @@ -9,6 +9,15 @@ namespace UnityEditor.ShaderGraph { static class FileUtilities { + public static string ReadAllTextUTF8(string path) + { + ReadOnlySpan contents = FileUtil.ReadAllBytes(path); + ReadOnlySpan bom = Encoding.UTF8.Preamble; + if (contents.StartsWith(bom)) + contents = contents[bom.Length..]; + return Encoding.UTF8.GetString(contents); + } + // if successfully written to disk, returns the serialized file contents as a string // on failure, returns null public static string WriteShaderGraphToDisk(string path, GraphData data) @@ -74,7 +83,7 @@ public static string SafeReadAllText(string assetPath) string result = null; try { - result = File.ReadAllText(FileUtil.PathToAbsolutePath(assetPath), Encoding.UTF8); + result = ReadAllTextUTF8(assetPath); } catch { @@ -87,7 +96,7 @@ internal static bool TryReadGraphDataFromDisk(string path, out GraphData graph) { try { - var textGraph = File.ReadAllText(FileUtil.PathToAbsolutePath(path), Encoding.UTF8); + var textGraph = ReadAllTextUTF8(path); graph = new GraphData { messageManager = new Graphing.Util.MessageManager(), From 4b6ea835eec4066f28a773b238fb0ec286b38875 Mon Sep 17 00:00:00 2001 From: Apoorva Joshi Date: Thu, 23 Apr 2026 22:20:49 +0000 Subject: [PATCH 51/56] URP: Default newly-created Universal Renderers to IntermediateTextureMode.Auto --- .../Runtime/UniversalRendererData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererData.cs index 26430b7dd94..e5db721026e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererData.cs @@ -153,7 +153,7 @@ static void CreateUniversalRendererData() [SerializeField] bool m_AccurateGbufferNormals = false; - [SerializeField] IntermediateTextureMode m_IntermediateTextureMode = IntermediateTextureMode.Always; + [SerializeField] IntermediateTextureMode m_IntermediateTextureMode = IntermediateTextureMode.Auto; [SerializeField] bool m_TileOnlyMode = false; /// From f7e834455502ff92004571b1b548db76fa691356 Mon Sep 17 00:00:00 2001 From: Alexey Zakharov Date: Fri, 24 Apr 2026 02:05:27 +0000 Subject: [PATCH 52/56] Profiler/renderpipeline/stage 5 remaining --- .../Runtime/Debugging/ProfilingScope.cs | 22 ++++++++++++++++- .../Lighting/ProbeVolume/ProbeBrickPool.cs | 2 +- .../ProbeReferenceVolume.Streaming.cs | 2 +- .../PathTracing/LightmapIntegration.cs | 4 ++-- .../PathTracing/LightmapIntegrationHelpers.cs | 24 +++++++++++++++---- .../Debugging/ProfilingSamplerTests.cs | 6 +++++ .../Runtime/Passes/ColorGradingLutPass.cs | 2 +- .../Passes/MainLightShadowCasterPass.cs | 2 +- .../Runtime/ReflectionProbeManager.cs | 2 +- 9 files changed, 54 insertions(+), 12 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs index d0f2d584ac9..9d70bbf752e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs @@ -392,7 +392,7 @@ public ProfilingScope(ProfilingSampler sampler) /// with this sample. The Profiler displays it in the sample hierarchy. [MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)] public ProfilingScope(ProfilingSampler sampler, Object contextObject) - : this(null, sampler, contextObject) + : this((CommandBuffer)null, sampler, contextObject) { } @@ -458,6 +458,26 @@ public ProfilingScope(BaseCommandBuffer cmd, ProfilingSampler sampler) #endif } + /// + /// Creates a profiling scope that records markers into as well as inline on the CPU, + /// and associates a Unity Object with the sample for identification in the Profiler. + /// + /// + /// Do not use with a named . A named command buffer inserts its own + /// scope marker on execution, which orphans the markers added here: the begin and end appear + /// inside different named-buffer execution brackets and will be mismatched in the Profiler timeline. + /// + /// BaseCommandBuffer (e.g. RasterCommandBuffer, UnsafeCommandBuffer) to receive the GPU-visible begin/end markers. + /// The sampler that provides the underlying marker. + /// May be null; the scope is a no-op in that case. + /// Unity Object (e.g. Texture, Mesh, Material) to associate + /// with this sample. The Profiler displays it in the sample hierarchy. + [MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)] + public ProfilingScope(BaseCommandBuffer cmd, ProfilingSampler sampler, Object contextObject) + : this(cmd.m_WrappedCommandBuffer, sampler, contextObject) + { + } + /// /// Ends the profiling scope by calling . Safe to call multiple times. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs index a6c51c68d2e..f6efc195f69 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs @@ -384,7 +384,7 @@ internal void Update(CommandBuffer cmd, CellStreamingScratchBuffer dataBuffer, C List dstLocations, bool updateSharedData, Texture validityTexture, ProbeVolumeSHBands bands, bool skyOcclusion, Texture skyOcclusionTexture, bool skyShadingDirections, Texture skyShadingDirectionsTexture, bool probeOcclusion) { - using (new ProfilingScope(cmd, CoreProfilingSamplers.APVDiskStreamingUpdatePool)) + using (new ProfilingScope(cmd, CoreProfilingSamplers.APVDiskStreamingUpdatePool, m_Pool.TexL0_L1rx)) { int chunkCount = dstLocations.Count; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs index 8d3d6d3efd1..aadc0724763 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs @@ -805,7 +805,7 @@ public void UpdateCellStreaming(CommandBuffer cmd, Camera camera, ProbeVolumesOp // Handle cell streaming for blending if (supportScenarioBlending) { - using (new ProfilingScope(cmd, CoreProfilingSamplers.APVScenarioBlendingUpdate)) + using (new ProfilingScope(cmd, CoreProfilingSamplers.APVScenarioBlendingUpdate, camera)) UpdateBlendingCellStreaming(cmd); } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs index 6b86b67ad98..729901a933a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs @@ -377,9 +377,9 @@ public void Accumulate( _accumulationShader.SetIntParam(cmd, LightmapIntegratorShaderIDs.SampleOffset, (int)currentSampleCountPerTexel); _accumulationShader.SetIntParam(cmd, LightmapIntegratorShaderIDs.MaxLocalSampleCount, (int)sampleCountToTakePerTexel); - cmd.BeginSample("Accumulation (Expanded)"); + cmd.BeginSample(LightmapIntegratorShaderIDs.k_AccumulationExpanded); _accumulationShader.Dispatch(cmd, traceScratchBuffer, _accumulationDispatchBuffer); - cmd.EndSample("Accumulation (Expanded)"); + cmd.EndSample(LightmapIntegratorShaderIDs.k_AccumulationExpanded); } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegrationHelpers.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegrationHelpers.cs index c9bd145971c..f5d1db7de22 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegrationHelpers.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegrationHelpers.cs @@ -68,6 +68,22 @@ internal static class ShaderIDs internal static int CopyTextureAdditiveKernel; internal static int MaskAlphaChannelKernel; + /// + /// Profiles the additive texture copy compute dispatch that blends a source region + /// into a destination region of a lightmap during accumulation. + /// + static readonly ProfilerMarker k_CopyTextureAdditive = + new ProfilerMarker(ProfilerCategory.Render, "CopyTextureAdditive", + MarkerFlags.Default | MarkerFlags.SampleGPU); + + /// + /// Profiles the alpha channel mask compute dispatch that clears or fills the alpha + /// channel of a lightmap texture to mark valid texel coverage. + /// + static readonly ProfilerMarker k_MaskAlphaChannel = + new ProfilerMarker(ProfilerCategory.Render, "MaskAlphaChannel", + MarkerFlags.Default | MarkerFlags.SampleGPU); + #if UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] static void ResetStaticsOnLoad() @@ -109,7 +125,7 @@ public void Load() public void CopyTextureAdditive(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, int width, int height, int sourceX = 0, int sourceY = 0, int destinationX = 0, int destinationY = 0) { - cmd.BeginSample("CopyTextureAdditive"); + cmd.BeginSample(k_CopyTextureAdditive); cmd.SetComputeTextureParam(ComputeHelperShader, CopyTextureAdditiveKernel, ShaderIDs.SourceTexture, source); cmd.SetComputeTextureParam(ComputeHelperShader, CopyTextureAdditiveKernel, ShaderIDs.DestinationTexture, destination); cmd.SetComputeIntParam(ComputeHelperShader, ShaderIDs.SourceWidth, width); @@ -120,18 +136,18 @@ public void CopyTextureAdditive(CommandBuffer cmd, RenderTargetIdentifier source cmd.SetComputeIntParam(ComputeHelperShader, ShaderIDs.DestinationY, destinationY); ComputeHelperShader.GetKernelThreadGroupSizes(CopyTextureAdditiveKernel, out uint groupX, out uint groupY, out _); cmd.DispatchCompute(ComputeHelperShader, CopyTextureAdditiveKernel, GraphicsHelpers.DivUp(width, groupX), GraphicsHelpers.DivUp(height, groupY), 1); - cmd.EndSample("CopyTextureAdditive"); + cmd.EndSample(k_CopyTextureAdditive); } public void MaskAlphaChannel(CommandBuffer cmd, RenderTargetIdentifier texture, int width, int height) { - cmd.BeginSample("MaskAlphaChannel"); + cmd.BeginSample(k_MaskAlphaChannel); cmd.SetComputeTextureParam(ComputeHelperShader, MaskAlphaChannelKernel, ShaderIDs.TextureInOut, texture); cmd.SetComputeIntParam(ComputeHelperShader, ShaderIDs.TextureWidth, width); cmd.SetComputeIntParam(ComputeHelperShader, ShaderIDs.TextureHeight, height); ComputeHelperShader.GetKernelThreadGroupSizes(MaskAlphaChannelKernel, out uint groupX, out uint groupY, out _); cmd.DispatchCompute(ComputeHelperShader, MaskAlphaChannelKernel, GraphicsHelpers.DivUp(width, groupX), GraphicsHelpers.DivUp(height, groupY), 1); - cmd.EndSample("MaskAlphaChannel"); + cmd.EndSample(k_MaskAlphaChannel); } } diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/Debugging/ProfilingSamplerTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/Debugging/ProfilingSamplerTests.cs index 646d14e20ae..633e617a709 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/Debugging/ProfilingSamplerTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/Debugging/ProfilingSamplerTests.cs @@ -44,9 +44,11 @@ public void Create_ReturnsNonNull() var sampler = ProfilingSampler.Create("CreatedMarker", MarkerFlags.Default); Assert.IsNotNull(sampler); Assert.IsTrue(sampler.IsValid()); +#if USE_RECORDER Assert.IsFalse(sampler.m_Recorder.Valid); Assert.IsFalse(sampler.m_GpuRecorder.Valid); Assert.IsFalse(sampler.m_InlineRecorder.Valid); +#endif } [Test] @@ -54,10 +56,12 @@ public void CreateWithFlags_IsValid() { var sampler = ProfilingSampler.Create("FlagsMarker", MarkerFlags.VerbosityAdvanced); Assert.IsTrue(sampler.IsValid()); +#if USE_RECORDER // Recorders are allocated lazily; none should be valid before enableRecording = true. Assert.IsFalse(sampler.m_Recorder.Valid); Assert.IsFalse(sampler.m_GpuRecorder.Valid); Assert.IsFalse(sampler.m_InlineRecorder.Valid); +#endif } [Test] @@ -113,6 +117,7 @@ public IEnumerator TimingProperties_ReturnZero_WhenNotRecording() Assert.AreEqual(0, m_Sampler.inlineCpuSampleCount); } +#if USE_RECORDER // Bits 10-12 all zero → SampleGPU auto-added → GpuRecorder is created on first enableRecording = true [Test] public void SampleGPU_AutoAdded_ForUserFacingMarker() @@ -245,5 +250,6 @@ public void Dispose_CalledTwice_DoesNotThrow() sampler.Dispose(); // recorders are no longer .Valid after first dispose }); } +#endif } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ColorGradingLutPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ColorGradingLutPass.cs index 00aea65cafd..c60285dde51 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ColorGradingLutPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ColorGradingLutPass.cs @@ -115,7 +115,7 @@ private static void ExecutePass(RasterCommandBuffer cmd, PassData passData, RTHa var lutBuilderHdr = passData.lutBuilderHdr; var allowColorGradingACESHDR = passData.allowColorGradingACESHDR; - using (new ProfilingScope(cmd, URPProfilingSamplers.ColorGradingLUT)) + using (new ProfilingScope(cmd, URPProfilingSamplers.ColorGradingLUT, passData.hdrGrading ? lutBuilderHdr : lutBuilderLdr)) { // TODO: should these components be set instead? diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs index a2740b39e74..d56c855313c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs @@ -268,7 +268,7 @@ void RenderMainLightCascadeShadowmap(RasterCommandBuffer cmd, ref PassData data) VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; - using (new ProfilingScope(cmd, URPProfilingSamplers.MainLightShadow)) + using (new ProfilingScope(cmd, URPProfilingSamplers.MainLightShadow, shadowLight.light)) { // Need to start by setting the Camera position and worldToCamera Matrix as that is not set for passes executed before normal rendering ShadowUtils.SetCameraPosition(cmd, data.cameraData.worldSpaceCameraPos); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ReflectionProbeManager.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ReflectionProbeManager.cs index a577c9ddf75..9b5a68c7613 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ReflectionProbeManager.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ReflectionProbeManager.cs @@ -300,7 +300,7 @@ public unsafe void UpdateGpuData(CommandBuffer cmd, ref CullingResults cullResul Debug.LogWarning("A number of reflection probes have been skipped due to the reflection probe atlas being full.\nTo fix this, you can decrease the number or resolution of probes."); } - using (new ProfilingScope(cmd, URPProfilingSamplers.UpdateReflectionProbeAtlas)) + using (new ProfilingScope(cmd, URPProfilingSamplers.UpdateReflectionProbeAtlas, m_AtlasTexture0)) { cmd.SetRenderTarget(m_AtlasTexture0); From f99d1f3ca3ff5c45cd59986c74e05669a20cb901 Mon Sep 17 00:00:00 2001 From: Cal Chiu Date: Fri, 24 Apr 2026 14:05:24 +0000 Subject: [PATCH 53/56] [UUM-138256] Added shader variant stripping for point sampling upsampling --- .../Editor/ShaderBuildPreprocessor.cs | 13 ++++++++++--- .../Editor/ShaderScriptableStripper.cs | 14 ++++++++++++++ .../UniversalRenderPipelineAssetPrefiltering.cs | 8 ++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderBuildPreprocessor.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderBuildPreprocessor.cs index cf15167d986..2d2c3769506 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderBuildPreprocessor.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderBuildPreprocessor.cs @@ -73,13 +73,14 @@ enum ShaderFeatures : long StencilLODCrossFade = (1L << 50), DeferredPlus = (1L << 51), ReflectionProbeAtlas = (1L << 52), + PointSamplingUpsampling = (1L << 53), #if SURFACE_CACHE - SurfaceCache = (1L << 53), + SurfaceCache = (1L << 54), #endif #if URP_SCREEN_SPACE_REFLECTION - ScreenSpaceReflection = (1L << 54), + ScreenSpaceReflection = (1L << 55), #endif - RenderObjectDepthInputAttachment = (1L << 55), + RenderObjectDepthInputAttachment = (1L << 56), All = ~0 } @@ -605,6 +606,9 @@ internal static ShaderFeatures GetSupportedShaderFeaturesFromAsset( if(urpAsset.allowPostProcessAlphaOutput) urpAssetShaderFeatures |= ShaderFeatures.AlphaOutput; + if (urpAsset.upscalingFilter == UpscalingFilterSelection.Point) + urpAssetShaderFeatures |= ShaderFeatures.PointSamplingUpsampling; + // Check each renderer & renderer feature urpAssetShaderFeatures = GetSupportedShaderFeaturesFromRenderers( ref urpAsset, @@ -1206,6 +1210,9 @@ ref List ssaoRendererFeatures spd.stripSSAOSampleCountHigh &= ssaoSettings.Samples != ScreenSpaceAmbientOcclusionSettings.AOSampleOption.High; } + // Upscaling + spd.stripPointSamplingUpsampling = !IsFeatureEnabled(shaderFeatures, ShaderFeatures.PointSamplingUpsampling); + return spd; } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderScriptableStripper.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderScriptableStripper.cs index 4f396807bd4..3950cda9543 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderScriptableStripper.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderScriptableStripper.cs @@ -116,6 +116,7 @@ public bool PassHasKeyword(LocalKeyword keyword) Shader m_StencilDeferred = Shader.Find("Hidden/Universal Render Pipeline/StencilDeferred"); Shader m_ClusterDeferred = Shader.Find("Hidden/Universal Render Pipeline/ClusterDeferred"); Shader m_UberPostShader = Shader.Find("Hidden/Universal Render Pipeline/UberPost"); + Shader m_FinalPostShader = Shader.Find("Hidden/Universal Render Pipeline/FinalPost"); Shader m_HDROutputBlitShader = Shader.Find("Hidden/Universal/BlitHDROverlay"); Shader m_DataDrivenLensFlareShader = Shader.Find("Hidden/Universal Render Pipeline/LensFlareDataDriven"); Shader m_ScreenSpaceLensFlareShader = Shader.Find("Hidden/Universal Render Pipeline/LensFlareScreenSpace"); @@ -201,6 +202,7 @@ public bool PassHasKeyword(LocalKeyword keyword) LocalKeyword m_ProceduralInstancing; LocalKeyword m_DepthAsInputAttachment; LocalKeyword m_DepthAsInputAttachmentMSAA; + LocalKeyword m_PointSampling; private LocalKeyword TryGetLocalKeyword(Shader shader, string name) { @@ -276,6 +278,7 @@ private void InitializeLocalShaderKeywords([DisallowNull] Shader shader) m_FilmGrain = TryGetLocalKeyword(shader, ShaderKeywordStrings.FilmGrain); m_SHPerVertex = TryGetLocalKeyword(shader, ShaderKeywordStrings.EVALUATE_SH_VERTEX); m_SHMixed = TryGetLocalKeyword(shader, ShaderKeywordStrings.EVALUATE_SH_MIXED); + m_PointSampling = TryGetLocalKeyword(shader, ShaderKeywordStrings.PointSampling); m_Instancing = TryGetLocalKeyword(shader, "INSTANCING_ON"); m_DotsInstancing = TryGetLocalKeyword(shader, "DOTS_INSTANCING_ON"); @@ -866,6 +869,14 @@ internal bool StripUnusedFeatures_CrossFadeLod(ref IShaderScriptableStrippingDat return !strippingData.IsShaderFeatureEnabled(ShaderFeatures.LODCrossFade); } + internal bool StripUnusedFeatures_PointSamplingUpsampling(ref IShaderScriptableStrippingData strippingData, ref ShaderStripTool stripTool) + { + if (strippingData.shader != m_UberPostShader && strippingData.shader != m_FinalPostShader) + return false; + + return stripTool.StripMultiCompile(m_PointSampling, ShaderFeatures.PointSamplingUpsampling); + } + internal bool StripUnusedFeatures(ref IShaderScriptableStrippingData strippingData) { if (StripUnusedFeatures_DebugDisplay(ref strippingData)) @@ -982,6 +993,9 @@ internal bool StripUnusedFeatures(ref IShaderScriptableStrippingData strippingDa if (StripUnusedFeatures_RenderObjectDepthInputAttachment(ref strippingData)) return true; + if (StripUnusedFeatures_PointSamplingUpsampling(ref strippingData, ref stripTool)) + return true; + return false; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAssetPrefiltering.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAssetPrefiltering.cs index 3554670c15e..c2d62cba8de 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAssetPrefiltering.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAssetPrefiltering.cs @@ -219,6 +219,10 @@ internal enum PrefilteringModeAdditionalLights [ShaderKeywordFilter.RemoveIf(true, keywordNames: ShaderKeywordStrings.ReflectionProbeAtlas)] [SerializeField] private bool m_PrefilterReflectionProbeAtlas = false; + // Point Sampling Upscaling (_POINT_SAMPLING) + [ShaderKeywordFilter.RemoveIf(true, keywordNames: ShaderKeywordStrings.PointSampling)] + [SerializeField] private bool m_PrefilterPointSamplingUpsampling = false; + /// /// Data used for Shader Prefiltering. Gathered after going through the URP Assets, /// Renderers and Renderer Features in OnPreprocessBuild() inside ShaderPreprocessor.cs. @@ -264,6 +268,8 @@ internal struct ShaderPrefilteringData public bool stripReflectionProbeBoxProjection; public bool stripReflectionProbeAtlas; + public bool stripPointSamplingUpsampling; + public bool stripScreenSpaceIrradiance; // Keyword used by the DepthNormalOnly pass to write smoothness into alpha channel for screen space reflections. @@ -331,6 +337,8 @@ internal void UpdateShaderKeywordPrefiltering(ref ShaderPrefilteringData prefilt m_PrefilterReflectionProbeBoxProjection = prefilteringData.stripReflectionProbeBoxProjection; m_PrefilterReflectionProbeAtlas = prefilteringData.stripReflectionProbeAtlas; + m_PrefilterPointSamplingUpsampling = prefilteringData.stripPointSamplingUpsampling; + m_PrefilterScreenSpaceIrradiance = prefilteringData.stripScreenSpaceIrradiance; m_PrefilterWriteSmoothness = prefilteringData.stripWriteSmoothness; From e32c02961ccac9db2fea2d5af0b081ce82feabc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nanho=20Lee=20=EF=BC=88=EC=9D=B4=EB=82=9C=ED=98=B8?= =?UTF-8?q?=EF=BC=89?= Date: Fri, 24 Apr 2026 14:05:25 +0000 Subject: [PATCH 54/56] Fix artifacts of applied rotational reflection probe --- .../Runtime/UniversalRenderPipeline.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index b048661a788..4e4e061ca01 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -1459,14 +1459,16 @@ static void SetSupportedRenderingFeatures(UniversalRenderPipelineAsset pipelineA particleSystemInstancing = true, overridesEnableLODCrossFade = true }; - if (GraphicsSettings.TryGetRenderPipelineSettings(out var reflectionProbeSettings) - && !reflectionProbeSettings.UseReflectionProbeRotation) - { - SupportedRenderingFeatures.active.reflectionProbeModes = SupportedRenderingFeatures.ReflectionProbeModes.None; - } SceneViewDrawMode.SetupDrawMode(); #endif + if (GraphicsSettings.TryGetRenderPipelineSettings(out var reflectionProbeSettings)) + { + SupportedRenderingFeatures.active.reflectionProbeModes = + reflectionProbeSettings.UseReflectionProbeRotation + ? SupportedRenderingFeatures.ReflectionProbeModes.Rotation + : SupportedRenderingFeatures.ReflectionProbeModes.None; + } SupportedRenderingFeatures.active.supportsHDR = pipelineAsset.supportsHDR; SupportedRenderingFeatures.active.rendersUIOverlay = true; From 5e94c4e6ec196ce0bc03ae501ecab73ca499036d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20V=C3=A1zquez=20Mart=C3=ADnez?= Date: Fri, 24 Apr 2026 14:05:27 +0000 Subject: [PATCH 55/56] [Material Upgrader] Generic system for URP and HDRP Menu item --- .../MaterialUpgrader.Utils.cs | 8 +-- .../MaterialUpgraderEditMenus.cs | 52 +++++++++++++++++++ .../MaterialUpgraderEditMenus.cs.meta | 2 + .../MaterialUpgraderEditMenus.cs | 38 -------------- .../MaterialUpgraderEditMenus.cs.meta | 2 - .../Editor/Wizard/HDWizard.cs | 7 ++- 6 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta delete mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs delete mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgrader.Utils.cs b/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgrader.Utils.cs index 8c4ab136b62..f1ba62b0caa 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgrader.Utils.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgrader.Utils.cs @@ -12,6 +12,8 @@ namespace UnityEditor.Rendering /// public partial class MaterialUpgrader { +internal static readonly string k_DialogKey = $"{nameof(UnityEditor)}.{nameof(Rendering)}.{nameof(MaterialUpgrader)}.ConfirmMaterialConversion"; + #region Internal API /// /// Represents an entry describing material properties @@ -344,15 +346,15 @@ static void PerformUpgrade(List materialUpgrades, List s_Empty = new List(); + + public static List GetCurrentSRPUpgraders() + { + if (!GraphicsSettings.isScriptableRenderPipelineEnabled) + return s_Empty; + + return MaterialUpgrader.FetchAllUpgradersForPipeline(GraphicsSettings.currentRenderPipelineAssetType); + } + + [MenuItem("Edit/Rendering/Materials/Convert All Built-In Materials to Current SRP", true)] + internal static bool UpgradeMaterialsProjectValidate() + { + return GraphicsSettings.isScriptableRenderPipelineEnabled; + } + + [MenuItem("Edit/Rendering/Materials/Convert All Built-In Materials to Current SRP", priority = CoreUtils.Priorities.editMenuPriority + 1)] + internal static void UpgradeMaterialsProject() + { + MaterialUpgrader.UpgradeProjectFolder(GetCurrentSRPUpgraders(), "Upgrade to SRP Material"); + } + + [MenuItem("Edit/Rendering/Materials/Convert Selected Built-In Materials to Current SRP", true)] + internal static bool UpgradeMaterialsSelectionValidate() + { + if (Selection.objects.Length == 0 || !GraphicsSettings.isScriptableRenderPipelineEnabled) + return false; + + foreach (var obj in Selection.objects) + { + if (obj is not Material) + return false; + } + + return true; + } + + [MenuItem("Edit/Rendering/Materials/Convert Selected Built-In Materials to Current SRP", priority = CoreUtils.Priorities.editMenuPriority + 2)] + internal static void UpgradeMaterialsSelection() + { + MaterialUpgrader.UpgradeSelection(GetCurrentSRPUpgraders(), "Upgrade to SRP Material"); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta new file mode 100644 index 00000000000..56a170e650f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 81cce92cea62afc46ae47b09fa3c8c6e \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs deleted file mode 100644 index 3181589f0e9..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Rendering; -using UnityEngine.Rendering.HighDefinition; - -namespace UnityEditor.Rendering.HighDefinition -{ - class MaterialUpgraderEditMenus - { - public static List GetHDUpgraders() - { - return MaterialUpgrader.FetchAllUpgradersForPipeline(typeof(HDRenderPipelineAsset)); - } - - [MenuItem("Edit/Rendering/Materials/Convert All Materials using HDRP upgraders", priority = CoreUtils.Priorities.editMenuPriority + 1)] - internal static void UpgradeMaterialsProject() - { - MaterialUpgrader.UpgradeProjectFolder(GetHDUpgraders(), "Upgrade to HDRP Material"); - } - - [MenuItem("Edit/Rendering/Materials/Convert Selected Materials using HDRP upgraders", true)] - static bool MaterialValidate(MenuCommand command) - { - foreach (var obj in Selection.objects) - { - if (obj is not Material) return false; - } - - return true; - } - - [MenuItem("Edit/Rendering/Materials/Convert Selected Materials using HDRP upgraders", priority = CoreUtils.Priorities.editMenuPriority + 2)] - internal static void UpgradeMaterialsSelection() - { - MaterialUpgrader.UpgradeSelection(GetHDUpgraders(), "Upgrade to HDRP Material"); - } - } -} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta deleted file mode 100644 index f1574a46878..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Tools/MaterialUpgrader/MaterialUpgraderEditMenus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 989185d0be859c14a8c6c5e7e8f9f46b \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.cs index f64b026d44c..388b27da51f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.cs @@ -391,6 +391,10 @@ private void UpdateWindowTitle() }); } + public static List GetHDUpgraders() + { + return MaterialUpgrader.FetchAllUpgradersForPipeline(typeof(HDRenderPipelineAsset)); + } private void CreateGUI() { UpdateWindowTitle(); @@ -431,8 +435,7 @@ private void CreateGUI() container.Add(CreateTitle(Style.migrationTitle)); - if (MaterialUpgrader.ProjectContainsNonAutomaticUpgradePath( - MaterialUpgraderEditMenus.GetHDUpgraders())) + if (MaterialUpgrader.ProjectContainsNonAutomaticUpgradePath(GetHDUpgraders())) { var nonBuiltinMaterialHelpBox = new HelpBox(Style.nonAutomaticUpgradeMaterials, HelpBoxMessageType.Warning); nonBuiltinMaterialHelpBox.AddToClassList("NonBuiltinMaterialWarning"); From 6fe86c994d59b0abf8084aa1d1d998a4ddfff2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolaj=20Z=C3=B8llner?= Date: Fri, 24 Apr 2026 14:05:34 +0000 Subject: [PATCH 56/56] Fixed missing parameter --- .../Tests/Editor/ShaderBuildPreprocessorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/ShaderBuildPreprocessorTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/ShaderBuildPreprocessorTests.cs index 28ec988257d..e6429719aee 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/ShaderBuildPreprocessorTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/ShaderBuildPreprocessorTests.cs @@ -112,7 +112,7 @@ internal void GetEveryShaderFeatureAndPrefilteringData(List rend internal ShaderFeatures GetSupportedShaderFeaturesFromAsset() { #if SURFACE_CACHE - return ShaderBuildPreprocessor.GetSupportedShaderFeaturesFromAsset(ref urpAsset, ref rendererShaderFeatures, ref ssaoRendererFeatures, stripUnusedVariants, out containsForwardRenderer, out containsSurfaceCache, out everyRendererHasSSAO); + return ShaderBuildPreprocessor.GetSupportedShaderFeaturesFromAsset(ref urpAsset, ref rendererShaderFeatures, ref ssaoRendererFeatures, stripUnusedVariants, out containsForwardRenderer, out containsSurfaceCache, out everyRendererHasSSAO, out everyRendererHasSSR); #else return ShaderBuildPreprocessor.GetSupportedShaderFeaturesFromAsset(ref urpAsset, ref rendererShaderFeatures, ref ssaoRendererFeatures, stripUnusedVariants, out containsForwardRenderer, out everyRendererHasSSAO, out everyRendererHasSSR); #endif