diff --git a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickIndex.cs b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickIndex.cs index 51968df97ed..1d6b22f7e22 100644 --- a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickIndex.cs +++ b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickIndex.cs @@ -23,6 +23,7 @@ internal class ProbeBrickIndex ComputeBuffer m_PhysicalIndexBuffer; int[] m_PhysicalIndexBufferData; + internal int estimatedVMemCost { get; private set; } [DebuggerDisplay("Brick [{position}, {subdivisionLevel}]")] [Serializable] @@ -103,6 +104,8 @@ internal ProbeBrickIndex(ProbeVolumeTextureMemoryBudget memoryBudget) m_PhysicalIndexBuffer = new ComputeBuffer(physicalBufferSize, sizeof(int), ComputeBufferType.Structured); m_NextFreeChunk = 0; + estimatedVMemCost = physicalBufferSize * sizeof(int); + // Should be done by a compute shader Clear(); Profiler.EndSample(); diff --git a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs index a642c8544ed..e8bce452a60 100644 --- a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs +++ b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeBrickPool.cs @@ -59,6 +59,8 @@ internal void Cleanup() internal const int kBrickProbeCountPerDim = kBrickCellCount + 1; internal const int kBrickProbeCountTotal = kBrickProbeCountPerDim * kBrickProbeCountPerDim * kBrickProbeCountPerDim; + internal int estimatedVMemCost { get; private set; } + const int kMaxPoolWidth = 1 << 11; // 2048 texels is a d3d11 limit for tex3d in all dimensions int m_AllocationSize; @@ -67,20 +69,25 @@ internal void Cleanup() BrickChunkAlloc m_NextFreeChunk; Stack m_FreeList; - internal ProbeBrickPool(int allocationSize, ProbeVolumeTextureMemoryBudget memoryBudget) + ProbeVolumeSHBands m_SHBands; + + internal ProbeBrickPool(int allocationSize, ProbeVolumeTextureMemoryBudget memoryBudget, ProbeVolumeSHBands shBands) { Profiler.BeginSample("Create ProbeBrickPool"); m_NextFreeChunk.x = m_NextFreeChunk.y = m_NextFreeChunk.z = 0; m_AllocationSize = allocationSize; m_MemoryBudget = memoryBudget; + m_SHBands = shBands; m_FreeList = new Stack(256); int width, height, depth; DerivePoolSizeFromBudget(allocationSize, memoryBudget, out width, out height, out depth); + int estimatedCost = 0; + m_Pool = CreateDataLocation(width * height * depth, false, shBands, out estimatedCost); + estimatedVMemCost = estimatedCost; - m_Pool = CreateDataLocation(width * height * depth, false, ProbeVolumeSHBands.SphericalHarmonicsL2); Profiler.EndSample(); } @@ -90,7 +97,9 @@ internal void EnsureTextureValidity() if (m_Pool.TexL0_L1rx == null) { m_Pool.Cleanup(); - m_Pool = CreateDataLocation(m_Pool.width * m_Pool.height * m_Pool.depth, false, ProbeVolumeSHBands.SphericalHarmonicsL2); + int estimatedCost = 0; + m_Pool = CreateDataLocation(m_Pool.width * m_Pool.height * m_Pool.depth, false, m_SHBands, out estimatedCost); + estimatedVMemCost = estimatedCost; } } @@ -213,26 +222,40 @@ static Vector3Int ProbeCountToDataLocSize(int numProbes) return new Vector3Int(width, height, depth); } - public static DataLocation CreateDataLocation(int numProbes, bool compressed, ProbeVolumeSHBands bands) + public static DataLocation CreateDataLocation(int numProbes, bool compressed, ProbeVolumeSHBands bands, out int allocatedBytes) { Vector3Int locSize = ProbeCountToDataLocSize(numProbes); int width = locSize.x; int height = locSize.y; int depth = locSize.z; + int texelCount = width * height * depth; + DataLocation loc; - loc.TexL0_L1rx = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGB_BC6H_UFloat : GraphicsFormat.R16G16B16A16_SFloat, TextureCreationFlags.None, 1); + allocatedBytes = 0; + loc.TexL0_L1rx = new Texture3D(width, height, depth, GraphicsFormat.R16G16B16A16_SFloat, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * 8; loc.TexL1_G_ry = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); + loc.TexL1_B_rz = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); if (bands == ProbeVolumeSHBands.SphericalHarmonicsL2) { loc.TexL2_0 = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); + loc.TexL2_1 = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); + loc.TexL2_2 = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); + loc.TexL2_3 = new Texture3D(width, height, depth, compressed ? GraphicsFormat.RGBA_BC7_UNorm : GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1); + allocatedBytes += texelCount * (compressed ? 1 : 4); } else { diff --git a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeIndexOfIndices.cs b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeIndexOfIndices.cs index 3ef50048ec1..2433acf4c93 100644 --- a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeIndexOfIndices.cs +++ b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeIndexOfIndices.cs @@ -12,6 +12,7 @@ namespace UnityEngine.Experimental.Rendering internal class ProbeCellIndices { const int kUintPerEntry = 3; + internal int estimatedVMemCost { get; private set; } internal struct IndexMetaData { @@ -20,7 +21,6 @@ internal struct IndexMetaData internal int firstChunkIndex; internal int minSubdiv; - internal void Pack(out uint[] vals) { vals = new uint[kUintPerEntry]; @@ -86,6 +86,7 @@ internal ProbeCellIndices(Vector3Int cellMin, Vector3Int cellMax, int cellSizeIn m_IndexOfIndicesBuffer = new ComputeBuffer(flatCellCount, kUintPerEntry * sizeof(uint)); m_IndexOfIndicesData = new uint[bufferSize]; m_NeedUpdateComputeBuffer = false; + estimatedVMemCost = flatCellCount * kUintPerEntry * sizeof(uint); } internal int GetFlatIdxForCell(Vector3Int cellPosition) diff --git a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs index 80642bb4607..a7692fb7344 100644 --- a/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs +++ b/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs @@ -229,6 +229,7 @@ public struct ProbeVolumeSystemParameters public Shader probeDebugShader; public ProbeVolumeSceneBounds sceneBounds; + public ProbeVolumeSHBands shBands; } public struct ProbeVolumeShadingParameters @@ -569,6 +570,7 @@ struct InitInfo #endif ProbeVolumeTextureMemoryBudget m_MemoryBudget; + ProbeVolumeSHBands m_SHBands; internal bool clearAssetsOnVolumeClear = false; @@ -611,8 +613,9 @@ public void Initialize(in ProbeVolumeSystemParameters parameters) } m_MemoryBudget = parameters.memoryBudget; + m_SHBands = parameters.shBands; InitializeDebug(parameters.probeDebugMesh, parameters.probeDebugShader); - InitProbeReferenceVolume(kProbeIndexPoolAllocationSize, m_MemoryBudget); + InitProbeReferenceVolume(kProbeIndexPoolAllocationSize, m_MemoryBudget, m_SHBands); m_IsInitialized = true; sceneBounds = parameters.sceneBounds; #if UNITY_EDITOR @@ -623,6 +626,7 @@ public void Initialize(in ProbeVolumeSystemParameters parameters) #endif } + /// /// Cleanup the Probe Volume system. /// public void Cleanup() @@ -638,6 +642,18 @@ public void Cleanup() m_IsInitialized = false; } + /// + /// Get approximate video memory impact, in bytes, of the system. + /// + /// An approximation of the video memory impact, in bytes, of the system + public int GetVideoMemoryCost() + { + if (!m_ProbeReferenceVolumeInit) + return 0; + + return m_Pool.estimatedVMemCost + m_Index.estimatedVMemCost + m_CellIndices.estimatedVMemCost; + } + void RemoveCell(Cell cell) { if (cell.loaded) @@ -762,7 +778,7 @@ void PerformPendingIndexChangeAndInit() if (m_NeedsIndexRebuild) { CleanupLoadedData(); - InitProbeReferenceVolume(kProbeIndexPoolAllocationSize, m_MemoryBudget); + InitProbeReferenceVolume(kProbeIndexPoolAllocationSize, m_MemoryBudget, m_SHBands); m_HasChangedIndex = true; m_NeedsIndexRebuild = false; } @@ -905,8 +921,9 @@ void LoadPendingCells(bool loadAll = false) var path = sortInfo.sourceAsset; bool compressed = false; - var dataLocation = ProbeBrickPool.CreateDataLocation(cell.sh.Length, compressed, ProbeVolumeSHBands.SphericalHarmonicsL2); - ProbeBrickPool.FillDataLocation(ref dataLocation, cell.sh, ProbeVolumeSHBands.SphericalHarmonicsL2); + int allocatedBytes = 0; + var dataLocation = ProbeBrickPool.CreateDataLocation(cell.sh.Length, compressed, m_SHBands, out allocatedBytes); + ProbeBrickPool.FillDataLocation(ref dataLocation, cell.sh, m_SHBands); cell.flatIdxInCellIndices = m_CellIndices.GetFlatIdxForCell(cell.position); @@ -952,14 +969,15 @@ public void PerformPendingOperations(bool loadAllCells = false) /// /// Size used for the chunk allocator that handles bricks. /// Probe reference volume memory budget. - void InitProbeReferenceVolume(int allocationSize, ProbeVolumeTextureMemoryBudget memoryBudget) + /// Probe reference volume SH bands. + void InitProbeReferenceVolume(int allocationSize, ProbeVolumeTextureMemoryBudget memoryBudget, ProbeVolumeSHBands shBands) { var minCellPosition = m_PendingInitInfo.pendingMinCellPosition; var maxCellPosition = m_PendingInitInfo.pendingMaxCellPosition; if (!m_ProbeReferenceVolumeInit) { Profiler.BeginSample("Initialize Reference Volume"); - m_Pool = new ProbeBrickPool(allocationSize, memoryBudget); + m_Pool = new ProbeBrickPool(allocationSize, memoryBudget, shBands); m_Index = new ProbeBrickIndex(memoryBudget); m_CellIndices = new ProbeCellIndices(minCellPosition, maxCellPosition, (int)Mathf.Pow(3, m_MaxSubdivision - 1)); @@ -1102,7 +1120,7 @@ RegId AddBricks(List bricks, ProbeBrickPool.DataLocation dataloc, ProbeBr } // Update the pool and index and ignore any potential frame latency related issues for now - m_Pool.Update(dataloc, m_TmpSrcChunks, ch_list, ProbeVolumeSHBands.SphericalHarmonicsL2); + m_Pool.Update(dataloc, m_TmpSrcChunks, ch_list, m_SHBands); m_BricksLoaded = true; diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index 3bb5e0ccb82..42f0333e6a1 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -219,6 +219,16 @@ static void Drawer_SectionProbeVolume(SerializedHDRenderPipelineAsset serialized EditorGUILayout.PropertyField(serialized.renderPipelineSettings.supportProbeVolume, Styles.supportProbeVolumeContent); EditorGUILayout.PropertyField(serialized.renderPipelineSettings.probeVolumeTextureSize, Styles.probeVolumeMemoryBudget); EditorGUILayout.PropertyField(serialized.renderPipelineSettings.probeVolumeSHBands, Styles.probeVolumeSHBands); + + int estimatedVMemCost = ProbeReferenceVolume.instance.GetVideoMemoryCost(); + if (estimatedVMemCost == 0) + { + EditorGUILayout.HelpBox($"Estimated GPU Memory cost 0.\nProbe reference volume is not used in the scene and resources haven't been allocated yet.", MessageType.Info, wide: true); + } + else + { + EditorGUILayout.HelpBox($"Estimated GPU Memory cost {estimatedVMemCost/(1000 * 1000)} MB.", MessageType.Info, wide: true); + } } else { diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 4702767ab6f..dba1b1a4854 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -381,7 +381,8 @@ public HDRenderPipeline(HDRenderPipelineAsset asset) memoryBudget = m_Asset.currentPlatformRenderPipelineSettings.probeVolumeMemoryBudget, probeDebugMesh = defaultResources.assets.sphereMesh, probeDebugShader = defaultResources.shaders.probeVolumeDebugShader, - sceneBounds = m_GlobalSettings.GetOrCreateAPVSceneBounds() + sceneBounds = m_GlobalSettings.GetOrCreateAPVSceneBounds(), + shBands = m_Asset.currentPlatformRenderPipelineSettings.probeVolumeSHBands }); RegisterRetrieveOfProbeVolumeExtraDataAction(); }