diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 2c2dbb99fba..096c3c82ef0 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fixed flickering of the game/scene view when lookdev is running. - Fixed some GCAlloc in the debug window. - Removed logic in the UI to disable parameters for contact shadows and fog volume components as it was going against the concept of the volume system. +- Fixed over consumption of GPU memory by the Physically Based Sky. ### Changed - Shadowmask and realtime reflection probe property are hide in Quality settings diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Creating-a-Custom-Sky.md b/com.unity.render-pipelines.high-definition/Documentation~/Creating-a-Custom-Sky.md index a165bdddd69..58efdb653bb 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/Creating-a-Custom-Sky.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/Creating-a-Custom-Sky.md @@ -59,6 +59,12 @@ public class NewSky : SkySettings } return hash; } + + public override int GetHashCode(Camera camera) + { + // Implement if your sky depends on the camera settings (like position for instance) + return GetHashCode(); + } } ``` @@ -159,6 +165,10 @@ class NewSkyRenderer : SkyRenderer } ``` +### Important note: +If your sky renderer has to manage heavy data (like precomputed textures or similar things) then particular care has to be taken. Indeed, one instance of the renderer will exist per camera so by default if this data is a member of the renderer, it willl also be duplicated in memory. +Since each sky renderer can have very different needs, the responsbility to share this kind of data is the renderer's and need to be implemented by the user. + ## Sky rendering Shader diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs index 3c15fd2be24..fe601292eb8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Collections.Generic; using System.Linq; using Utilities; @@ -18,6 +19,7 @@ namespace UnityEngine.Rendering.HighDefinition /// HDCamera class. /// This class holds all information for a given camera. Constants used for shading as well as buffers persistent from one frame to another etc. /// + [DebuggerDisplay("({camera.name})")] public class HDCamera { #region Public API diff --git a/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSky.cs b/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSky.cs index 202f4be7312..03bb3b49385 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSky.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSky.cs @@ -289,24 +289,6 @@ internal int GetPrecomputationHashCode() unchecked { #if UNITY_2019_3 // In 2019.3, when we call GetHashCode on a VolumeParameter it generate garbage (due to the boxing of the generic parameter) - // These parameters affect precomputation. - hash = hash * 23 + earthPreset.value.GetHashCode(); - hash = hash * 23 + planetaryRadius.value.GetHashCode(); - hash = hash * 23 + groundTint.value.GetHashCode(); - - hash = hash * 23 + airMaximumAltitude.value.GetHashCode(); - hash = hash * 23 + airDensityR.value.GetHashCode(); - hash = hash * 23 + airDensityG.value.GetHashCode(); - hash = hash * 23 + airDensityB.value.GetHashCode(); - hash = hash * 23 + airTint.value.GetHashCode(); - - hash = hash * 23 + aerosolMaximumAltitude.value.GetHashCode(); - hash = hash * 23 + aerosolDensity.value.GetHashCode(); - hash = hash * 23 + aerosolTint.value.GetHashCode(); - hash = hash * 23 + aerosolAnisotropy.value.GetHashCode(); - - hash = hash * 23 + numberOfBounces.value.GetHashCode(); - // These parameters affect precomputation. hash = hash * 23 + earthPreset.overrideState.GetHashCode(); hash = hash * 23 + planetaryRadius.overrideState.GetHashCode(); @@ -376,32 +358,6 @@ public override int GetHashCode() { #if UNITY_2019_3 // In 2019.3, when we call GetHashCode on a VolumeParameter it generate garbage (due to the boxing of the generic parameter) // These parameters do NOT affect precomputation. - hash = hash * 23 + sphericalMode.value.GetHashCode(); - hash = hash * 23 + seaLevel.value.GetHashCode(); - hash = hash * 23 + planetCenterPosition.value.GetHashCode(); - hash = hash * 23 + planetRotation.value.GetHashCode(); - - if (groundColorTexture.value != null) - hash = hash * 23 + groundColorTexture.value.GetHashCode(); - - if (groundEmissionTexture.value != null) - hash = hash * 23 + groundEmissionTexture.value.GetHashCode(); - - hash = hash * 23 + groundEmissionMultiplier.value.GetHashCode(); - - hash = hash * 23 + spaceRotation.value.GetHashCode(); - - if (spaceEmissionTexture.value != null) - hash = hash * 23 + spaceEmissionTexture.value.GetHashCode(); - - hash = hash * 23 + spaceEmissionMultiplier.value.GetHashCode(); - hash = hash * 23 + colorSaturation.value.GetHashCode(); - hash = hash * 23 + alphaSaturation.value.GetHashCode(); - hash = hash * 23 + alphaMultiplier.value.GetHashCode(); - hash = hash * 23 + horizonTint.value.GetHashCode(); - hash = hash * 23 + zenithTint.value.GetHashCode(); - hash = hash * 23 + horizonZenithShift.value.GetHashCode(); - hash = hash * 23 + sphericalMode.overrideState.GetHashCode(); hash = hash * 23 + seaLevel.overrideState.GetHashCode(); hash = hash * 23 + planetCenterPosition.overrideState.GetHashCode(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs b/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs index 6c206f55888..03767aec550 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs @@ -1,10 +1,291 @@ using System; +using System.Collections.Generic; using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.HighDefinition { class PhysicallyBasedSkyRenderer : SkyRenderer { + class PrecomputationCache + { + class RefCountedData + { + public int refCount; + public PrecomputationData data = new PrecomputationData(); + } + + ObjectPool m_DataPool = new ObjectPool(null, null); + Dictionary m_CachedData = new Dictionary(); + + public PrecomputationData Get(int hash) + { + RefCountedData result; + if (m_CachedData.TryGetValue(hash, out result)) + { + result.refCount++; + return result.data; + } + else + { + result = m_DataPool.Get(); + result.refCount = 1; + result.data.Allocate(); + m_CachedData.Add(hash, result); + return result.data; + } + } + + public void Release(int hash) + { + if (m_CachedData.TryGetValue(hash, out var result)) + { + result.refCount--; + if (result.refCount == 0) + { + result.data.Release(); + m_CachedData.Remove(hash); + m_DataPool.Release(result); + } + } + } + } + + class PrecomputationData + { + // We compute at most one bounce per frame for perf reasons. + // We need to store the frame index because more than one render can happen during a frame (cubemap update + regular rendering). + int m_LastPrecomputedBounce; + int m_LastFrameComputation; + + RTHandle[] m_GroundIrradianceTables; // All orders, one order + RTHandle[] m_InScatteredRadianceTables; // Air SS, Aerosol SS, Atmosphere MS, Atmosphere one order, Temp + + RTHandle AllocateGroundIrradianceTable(int index) + { + var table = RTHandles.Alloc((int)PbrSkyConfig.GroundIrradianceTableSize, 1, + colorFormat: s_ColorFormat, + enableRandomWrite: true, + name: string.Format("GroundIrradianceTable{0}", index)); + + Debug.Assert(table != null); + + return table; + } + + RTHandle AllocateInScatteredRadianceTable(int index) + { + // Emulate a 4D texture with a "deep" 3D texture. + var table = RTHandles.Alloc((int)PbrSkyConfig.InScatteredRadianceTableSizeX, + (int)PbrSkyConfig.InScatteredRadianceTableSizeY, + (int)PbrSkyConfig.InScatteredRadianceTableSizeZ * + (int)PbrSkyConfig.InScatteredRadianceTableSizeW, + dimension: TextureDimension.Tex3D, + colorFormat: s_ColorFormat, + enableRandomWrite: true, + name: string.Format("InScatteredRadianceTable{0}", index)); + + Debug.Assert(table != null); + + return table; + } + + public void Allocate() + { + m_LastFrameComputation = -1; + m_LastPrecomputedBounce = 0; + + // No temp tables. + m_GroundIrradianceTables = new RTHandle[2]; + m_GroundIrradianceTables[0] = AllocateGroundIrradianceTable(0); + + m_InScatteredRadianceTables = new RTHandle[5]; + m_InScatteredRadianceTables[0] = AllocateInScatteredRadianceTable(0); + m_InScatteredRadianceTables[1] = AllocateInScatteredRadianceTable(1); + m_InScatteredRadianceTables[2] = AllocateInScatteredRadianceTable(2); + } + + public void Release() + { + RTHandles.Release(m_GroundIrradianceTables[0]); m_GroundIrradianceTables[0] = null; + RTHandles.Release(m_GroundIrradianceTables[1]); m_GroundIrradianceTables[1] = null; + RTHandles.Release(m_InScatteredRadianceTables[0]); m_InScatteredRadianceTables[0] = null; + RTHandles.Release(m_InScatteredRadianceTables[1]); m_InScatteredRadianceTables[1] = null; + RTHandles.Release(m_InScatteredRadianceTables[2]); m_InScatteredRadianceTables[2] = null; + RTHandles.Release(m_InScatteredRadianceTables[3]); m_InScatteredRadianceTables[3] = null; + RTHandles.Release(m_InScatteredRadianceTables[4]); m_InScatteredRadianceTables[4] = null; + } + + void PrecomputeTables(CommandBuffer cmd) + { + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.InScatteredRadiancePrecomputation))) + { + int order = m_LastPrecomputedBounce + 1; + { + // For efficiency reasons, multiple scattering is computed in 2 passes: + // 1. Gather the in-scattered radiance over the entire sphere of directions. + // 2. Accumulate the in-scattered radiance along the ray. + // Single scattering performs both steps during the same pass. + + int firstPass = Math.Min(order - 1, 2); + int accumPass = 3; + int numPasses = Math.Min(order, 2); + + for (int i = 0; i < numPasses; i++) + { + int pass = (i == 0) ? firstPass : accumPass; + + switch (pass) + { + case 0: + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AirSingleScatteringTable, m_InScatteredRadianceTables[0]); + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AerosolSingleScatteringTable, m_InScatteredRadianceTables[1]); + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[2]); // MS orders + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTableOrder, m_InScatteredRadianceTables[3]); // One order + break; + case 1: + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[1]); // One order + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[4]); // Temp + break; + case 2: + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[3]); // One order + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[1]); // One order + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[4]); // Temp + break; + case 3: + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[4]); // Temp + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTableOrder, m_InScatteredRadianceTables[3]); // One order + cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[2]); // MS orders + break; + default: + Debug.Assert(false); + break; + } + + // Re-illuminate the sky with each bounce. + // Emulate a 4D dispatch with a "deep" 3D dispatch. + cmd.DispatchCompute(s_InScatteredRadiancePrecomputationCS, pass, (int)PbrSkyConfig.InScatteredRadianceTableSizeX / 4, + (int)PbrSkyConfig.InScatteredRadianceTableSizeY / 4, + (int)PbrSkyConfig.InScatteredRadianceTableSizeZ / 4 * + (int)PbrSkyConfig.InScatteredRadianceTableSizeW); + } + + { + // Used by all passes. + cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._GroundIrradianceTable, m_GroundIrradianceTables[0]); // All orders + cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._GroundIrradianceTableOrder, m_GroundIrradianceTables[1]); // One order + } + + switch (firstPass) + { + case 0: + break; + case 1: + cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); + cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); + break; + case 2: + cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[3]); // One order + break; + default: + Debug.Assert(false); + break; + } + + // Re-illuminate the ground with each bounce. + cmd.DispatchCompute(s_GroundIrradiancePrecomputationCS, firstPass, (int)PbrSkyConfig.GroundIrradianceTableSize / 64, 1, 1); + } + } + } + + public void BindGlobalBuffers(CommandBuffer cmd) + { + // TODO: ground irradiance table? Volume SH? Something else? + if (m_LastPrecomputedBounce > 0) + { + cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); + cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); + cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]); + } + else + { + cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, CoreUtils.blackVolumeTexture); + cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, CoreUtils.blackVolumeTexture); + cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, CoreUtils.blackVolumeTexture); + } + } + + public void BindBuffers(CommandBuffer cmd, MaterialPropertyBlock mpb) + { + if (m_LastPrecomputedBounce != 0) + { + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[0]); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]); + } + else + { + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundIrradianceTexture, Texture2D.blackTexture); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AirSingleScatteringTexture, CoreUtils.blackVolumeTexture); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AerosolSingleScatteringTexture, CoreUtils.blackVolumeTexture); + s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._MultipleScatteringTexture, CoreUtils.blackVolumeTexture); + } + + } + + public bool Update(BuiltinSkyParameters builtinParams, PhysicallyBasedSky pbrSky) + { + if (builtinParams.frameIndex <= m_LastFrameComputation) + return false; + + m_LastFrameComputation = builtinParams.frameIndex; + + if (m_LastPrecomputedBounce == 0) + { + // Allocate temp tables if needed + if (m_GroundIrradianceTables[1] == null) + { + m_GroundIrradianceTables[1] = AllocateGroundIrradianceTable(1); + } + + if (m_InScatteredRadianceTables[3] == null) + { + m_InScatteredRadianceTables[3] = AllocateInScatteredRadianceTable(3); + } + + if (m_InScatteredRadianceTables[4] == null) + { + m_InScatteredRadianceTables[4] = AllocateInScatteredRadianceTable(4); + } + } + + if (m_LastPrecomputedBounce == pbrSky.numberOfBounces.value) + { + // Free temp tables. + // This is a deferred release (one frame late)! + RTHandles.Release(m_GroundIrradianceTables[1]); + RTHandles.Release(m_InScatteredRadianceTables[3]); + RTHandles.Release(m_InScatteredRadianceTables[4]); + m_GroundIrradianceTables[1] = null; + m_InScatteredRadianceTables[3] = null; + m_InScatteredRadianceTables[4] = null; + } + + if (m_LastPrecomputedBounce < pbrSky.numberOfBounces.value) + { + PrecomputeTables(builtinParams.commandBuffer); + m_LastPrecomputedBounce++; + + // If the sky is realtime, an upcoming update will update the sky lighting. Otherwise we need to force an update. + return builtinParams.skySettings.updateMode != EnvironmentUpdateMode.Realtime; + } + + return false; + } + } + [GenerateHLSL] public enum PbrSkyConfig { @@ -22,49 +303,18 @@ public enum PbrSkyConfig // If the hash does not match, we must recompute our data. int m_LastPrecomputationParamHash; - // We compute at most one bounce per frame for perf reasons. - // We need to store the frame index because more than one render can happen during a frame (cubemap update + regular rendering). - int m_LastPrecomputedBounce; - // Precomputed data below. - RTHandle[] m_GroundIrradianceTables; // All orders, one order - RTHandle[] m_InScatteredRadianceTables; // Air SS, Aerosol SS, Atmosphere MS, Atmosphere one order, Temp + PrecomputationData m_PrecomputedData; static ComputeShader s_GroundIrradiancePrecomputationCS; static ComputeShader s_InScatteredRadiancePrecomputationCS; - Material s_PbrSkyMaterial; + Material m_PbrSkyMaterial; static MaterialPropertyBlock s_PbrSkyMaterialProperties; - static GraphicsFormat s_ColorFormat = GraphicsFormat.R16G16B16A16_SFloat; - - RTHandle AllocateGroundIrradianceTable(int index) - { - var table = RTHandles.Alloc((int)PbrSkyConfig.GroundIrradianceTableSize, 1, - colorFormat: s_ColorFormat, - enableRandomWrite: true, - name: string.Format("GroundIrradianceTable{0}", index)); + static PrecomputationCache s_PrecomputaionCache = new PrecomputationCache(); - Debug.Assert(table != null); - - return table; - } + static GraphicsFormat s_ColorFormat = GraphicsFormat.R16G16B16A16_SFloat; - RTHandle AllocateInScatteredRadianceTable(int index) - { - // Emulate a 4D texture with a "deep" 3D texture. - var table = RTHandles.Alloc((int)PbrSkyConfig.InScatteredRadianceTableSizeX, - (int)PbrSkyConfig.InScatteredRadianceTableSizeY, - (int)PbrSkyConfig.InScatteredRadianceTableSizeZ * - (int)PbrSkyConfig.InScatteredRadianceTableSizeW, - dimension: TextureDimension.Tex3D, - colorFormat: s_ColorFormat, - enableRandomWrite: true, - name: string.Format("InScatteredRadianceTable{0}", index)); - - Debug.Assert(table != null); - - return table; - } public PhysicallyBasedSkyRenderer() { @@ -80,54 +330,28 @@ public override void Build() s_InScatteredRadiancePrecomputationCS = hdrpResources.shaders.inScatteredRadiancePrecomputationCS; s_PbrSkyMaterialProperties = new MaterialPropertyBlock(); - s_PbrSkyMaterial = CoreUtils.CreateEngineMaterial(hdrpResources.shaders.physicallyBasedSkyPS); + m_PbrSkyMaterial = CoreUtils.CreateEngineMaterial(hdrpResources.shaders.physicallyBasedSkyPS); Debug.Assert(s_GroundIrradiancePrecomputationCS != null); Debug.Assert(s_InScatteredRadiancePrecomputationCS != null); - - // No temp tables. - m_GroundIrradianceTables = new RTHandle[2]; - m_GroundIrradianceTables[0] = AllocateGroundIrradianceTable(0); - - m_InScatteredRadianceTables = new RTHandle[5]; - m_InScatteredRadianceTables[0] = AllocateInScatteredRadianceTable(0); - m_InScatteredRadianceTables[1] = AllocateInScatteredRadianceTable(1); - m_InScatteredRadianceTables[2] = AllocateInScatteredRadianceTable(2); } public override void SetGlobalSkyData(CommandBuffer cmd, BuiltinSkyParameters builtinParams) { UpdateGlobalConstantBuffer(cmd, builtinParams); - - // TODO: ground irradiance table? Volume SH? Something else? - if (m_LastPrecomputedBounce > 0) - { - cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); - cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); - cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]); - } - else - { - cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, CoreUtils.blackVolumeTexture); - cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, CoreUtils.blackVolumeTexture); - cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, CoreUtils.blackVolumeTexture); - } - + if (m_PrecomputedData != null) + m_PrecomputedData.BindGlobalBuffers(builtinParams.commandBuffer); } public override void Cleanup() { - RTHandles.Release(m_GroundIrradianceTables[0]); m_GroundIrradianceTables[0] = null; - RTHandles.Release(m_GroundIrradianceTables[1]); m_GroundIrradianceTables[1] = null; - RTHandles.Release(m_InScatteredRadianceTables[0]); m_InScatteredRadianceTables[0] = null; - RTHandles.Release(m_InScatteredRadianceTables[1]); m_InScatteredRadianceTables[1] = null; - RTHandles.Release(m_InScatteredRadianceTables[2]); m_InScatteredRadianceTables[2] = null; - RTHandles.Release(m_InScatteredRadianceTables[3]); m_InScatteredRadianceTables[3] = null; - RTHandles.Release(m_InScatteredRadianceTables[4]); m_InScatteredRadianceTables[4] = null; - - CoreUtils.Destroy(s_PbrSkyMaterial); - - m_LastPrecomputedBounce = 0; + if (m_PrecomputedData != null) + { + s_PrecomputaionCache.Release(m_LastPrecomputationParamHash); + m_LastPrecomputationParamHash = 0; + m_PrecomputedData = null; + } + CoreUtils.Destroy(m_PbrSkyMaterial); } static float CornetteShanksPhasePartConstant(float anisotropy) @@ -197,90 +421,6 @@ void UpdateGlobalConstantBuffer(CommandBuffer cmd, BuiltinSkyParameters builtinP cmd.SetGlobalFloat( HDShaderIDs._HorizonZenithShiftScale, expParams.y); } - void PrecomputeTables(CommandBuffer cmd) - { - using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.InScatteredRadiancePrecomputation))) - { - int order = m_LastPrecomputedBounce + 1; - { - // For efficiency reasons, multiple scattering is computed in 2 passes: - // 1. Gather the in-scattered radiance over the entire sphere of directions. - // 2. Accumulate the in-scattered radiance along the ray. - // Single scattering performs both steps during the same pass. - - int firstPass = Math.Min(order - 1, 2); - int accumPass = 3; - int numPasses = Math.Min(order, 2); - - for (int i = 0; i < numPasses; i++) - { - int pass = (i == 0) ? firstPass : accumPass; - - switch (pass) - { - case 0: - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AirSingleScatteringTable, m_InScatteredRadianceTables[0]); - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AerosolSingleScatteringTable, m_InScatteredRadianceTables[1]); - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[2]); // MS orders - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTableOrder, m_InScatteredRadianceTables[3]); // One order - break; - case 1: - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[1]); // One order - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[4]); // Temp - break; - case 2: - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[3]); // One order - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[1]); // One order - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[4]); // Temp - break; - case 3: - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[4]); // Temp - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTableOrder, m_InScatteredRadianceTables[3]); // One order - cmd.SetComputeTextureParam(s_InScatteredRadiancePrecomputationCS, pass, HDShaderIDs._MultipleScatteringTable, m_InScatteredRadianceTables[2]); // MS orders - break; - default: - Debug.Assert(false); - break; - } - - // Re-illuminate the sky with each bounce. - // Emulate a 4D dispatch with a "deep" 3D dispatch. - cmd.DispatchCompute(s_InScatteredRadiancePrecomputationCS, pass, (int)PbrSkyConfig.InScatteredRadianceTableSizeX / 4, - (int)PbrSkyConfig.InScatteredRadianceTableSizeY / 4, - (int)PbrSkyConfig.InScatteredRadianceTableSizeZ / 4 * - (int)PbrSkyConfig.InScatteredRadianceTableSizeW); - } - - { - // Used by all passes. - cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._GroundIrradianceTable, m_GroundIrradianceTables[0]); // All orders - cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._GroundIrradianceTableOrder, m_GroundIrradianceTables[1]); // One order - } - - switch (firstPass) - { - case 0: - break; - case 1: - cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); - cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); - break; - case 2: - cmd.SetComputeTextureParam(s_GroundIrradiancePrecomputationCS, firstPass, HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[3]); // One order - break; - default: - Debug.Assert(false); - break; - } - - // Re-illuminate the ground with each bounce. - cmd.DispatchCompute(s_GroundIrradiancePrecomputationCS, firstPass, (int)PbrSkyConfig.GroundIrradianceTableSize / 64, 1, 1); - } - } - } - protected override bool Update(BuiltinSkyParameters builtinParams) { UpdateGlobalConstantBuffer(builtinParams.commandBuffer, builtinParams); @@ -289,54 +429,13 @@ protected override bool Update(BuiltinSkyParameters builtinParams) int currPrecomputationParamHash = pbrSky.GetPrecomputationHashCode(); if (currPrecomputationParamHash != m_LastPrecomputationParamHash) { - // Hash does not match, have to restart the precomputation from scratch. - m_LastPrecomputedBounce = 0; - } - - if (m_LastPrecomputedBounce == 0) - { - // Allocate temp tables if needed - if (m_GroundIrradianceTables[1] == null) - { - m_GroundIrradianceTables[1] = AllocateGroundIrradianceTable(1); - } - - if (m_InScatteredRadianceTables[3] == null) - { - m_InScatteredRadianceTables[3] = AllocateInScatteredRadianceTable(3); - } - - if (m_InScatteredRadianceTables[4] == null) - { - m_InScatteredRadianceTables[4] = AllocateInScatteredRadianceTable(4); - } - } - - if (m_LastPrecomputedBounce == pbrSky.numberOfBounces.value) - { - // Free temp tables. - // This is a deferred release (one frame late)! - RTHandles.Release(m_GroundIrradianceTables[1]); - RTHandles.Release(m_InScatteredRadianceTables[3]); - RTHandles.Release(m_InScatteredRadianceTables[4]); - m_GroundIrradianceTables[1] = null; - m_InScatteredRadianceTables[3] = null; - m_InScatteredRadianceTables[4] = null; - } - - if (m_LastPrecomputedBounce < pbrSky.numberOfBounces.value) - { - PrecomputeTables(builtinParams.commandBuffer); - m_LastPrecomputedBounce++; - - // Update the hash for the current bounce. + if (m_LastPrecomputationParamHash != 0) + s_PrecomputaionCache.Release(m_LastPrecomputationParamHash); + m_PrecomputedData = s_PrecomputaionCache.Get(currPrecomputationParamHash); m_LastPrecomputationParamHash = currPrecomputationParamHash; - - // If the sky is realtime, an upcoming update will update the sky lighting. Otherwise we need to force an update. - return builtinParams.skySettings.updateMode != EnvironmentUpdateMode.Realtime; } - return false; + return m_PrecomputedData.Update(builtinParams, pbrSky); } // 'renderSunDisk' parameter is not supported. @@ -370,20 +469,7 @@ public override void RenderSky(BuiltinSkyParameters builtinParams, bool renderFo s_PbrSkyMaterialProperties.SetMatrix(HDShaderIDs._PlanetRotation, Matrix4x4.Rotate(planetRotation)); s_PbrSkyMaterialProperties.SetMatrix(HDShaderIDs._SpaceRotation, Matrix4x4.Rotate(spaceRotation)); - if (m_LastPrecomputedBounce != 0) - { - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundIrradianceTexture, m_GroundIrradianceTables[0]); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AirSingleScatteringTexture, m_InScatteredRadianceTables[0]); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AerosolSingleScatteringTexture, m_InScatteredRadianceTables[1]); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._MultipleScatteringTexture, m_InScatteredRadianceTables[2]); - } - else - { - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._GroundIrradianceTexture, Texture2D.blackTexture); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AirSingleScatteringTexture, CoreUtils.blackVolumeTexture); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._AerosolSingleScatteringTexture, CoreUtils.blackVolumeTexture); - s_PbrSkyMaterialProperties.SetTexture(HDShaderIDs._MultipleScatteringTexture, CoreUtils.blackVolumeTexture); - } + m_PrecomputedData.BindBuffers(cmd, s_PbrSkyMaterialProperties); int hasGroundAlbedoTexture = 0; @@ -418,7 +504,7 @@ public override void RenderSky(BuiltinSkyParameters builtinParams, bool renderFo int pass = (renderForCubemap ? 0 : 2) + (isPbrSkyActive ? 0 : 1); - CoreUtils.DrawFullScreen(builtinParams.commandBuffer, s_PbrSkyMaterial, s_PbrSkyMaterialProperties, pass); + CoreUtils.DrawFullScreen(builtinParams.commandBuffer, m_PbrSkyMaterial, s_PbrSkyMaterialProperties, pass); } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUpdateContext.cs b/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUpdateContext.cs index 3ae3591daa4..9127a4824f0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUpdateContext.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUpdateContext.cs @@ -16,6 +16,15 @@ public SkySettings skySettings get { return m_SkySettings; } set { + // We cleanup the renderer first here because in some cases, after scene unload, the skySettings field will be "null" because the object got destroyed. + // In this case, the renderer might stay allocated until a non null value is set. To avoid a lingering allocation, we cleanup first before anything else. + // So next frame after scene unload, renderer will be freed. + if (skyRenderer != null && (value == null || value.GetSkyRendererType() != skyRenderer.GetType())) + { + skyRenderer.Cleanup(); + skyRenderer = null; + } + if (m_SkySettings == value) return; @@ -23,13 +32,8 @@ public SkySettings skySettings m_SkySettings = value; currentUpdateTime = 0.0f; - if (m_SkySettings != null && (skyRenderer == null || m_SkySettings.GetSkyRendererType() != skyRenderer.GetType())) + if (m_SkySettings != null && skyRenderer == null) { - if (skyRenderer != null) - { - skyRenderer.Cleanup(); - } - var rendererType = m_SkySettings.GetSkyRendererType(); skyRenderer = (SkyRenderer)Activator.CreateInstance(rendererType); skyRenderer.Build();