From 64ccbca294812e7392585e2742ed35c09d62f658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 10 Jun 2020 15:31:50 +0200 Subject: [PATCH 1/3] Fixed 1253367 by rebaking probe with missing baked texture. --- .../Runtime/Common/ListBuffer.cs | 163 ++++++++++++++++++ .../Runtime/Common/ListBuffer.cs.meta | 3 + .../Reflection/HDBakedReflectionSystem.cs | 83 +++++++-- 3 files changed, 235 insertions(+), 14 deletions(-) create mode 100644 com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs create mode 100644 com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs.meta diff --git a/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs new file mode 100644 index 00000000000..756f83cc66f --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs @@ -0,0 +1,163 @@ +using System; +using Unity.Collections.LowLevel.Unsafe; + +namespace UnityEngine.Rendering +{ + /// + /// A list that stores value on a provided memory buffer. + /// + /// Usually use this to have a list on stack allocated memory. + /// + /// The type of the data stored in the list. + public unsafe struct ListBuffer + where T: unmanaged + { + private T* m_BufferPtr; + private int m_Capacity; + private int* m_CountPtr; + + /// + /// The pointer to the memory storage. + /// + internal T* BufferPtr => m_BufferPtr; + + /// + /// The number of item in the list. + /// + public int Count => *m_CountPtr; + + /// + /// The maximum number of item stored in this list. + /// + public int Capacity => m_Capacity; + + /// + /// Instantiate a new list. + /// + /// The address in memory to store the data. + /// The address in memory to store the number of item of this list.. + /// The number of that can be stored in the buffer. + public ListBuffer(T* bufferPtr, int* countPtr, int capacity) + { + m_BufferPtr = bufferPtr; + m_Capacity = capacity; + m_CountPtr = countPtr; + } + + /// + /// Get an item from the list. + /// + /// The index of the item to get. + /// A reference to the item. + /// If the index is invalid. + public ref T this[in int index] + { + get + { + if (index < 0 || index >= Count) + throw new IndexOutOfRangeException( + $"Expected a value between 0 and {Count}, but received {index}."); + return ref m_BufferPtr[index]; + } + } + + /// + /// Get an item from the list. + /// + /// Safety: index must be inside the bounds of the list. + /// + /// The index of the item to get. + /// A reference to the item. + public unsafe ref T GetUnchecked(in int index) => ref m_BufferPtr[index]; + + /// + /// Try to add a value in the list. + /// + /// A reference to the value to add. + /// + /// true when the value was added, + /// false when the value was not added because the capacity was reached. + /// + public bool TryAdd(in T value) + { + if (Count >= m_Capacity) + return false; + + m_BufferPtr[Count] = value; + ++*m_CountPtr; + return true; + } + + /// + /// Copy the content of this list into another buffer in memory. + /// + /// Safety: + /// * The destination must have enough memory to receive the copied data. + /// + /// The destination buffer of the copy operation. + /// The index of the first element that will be copied in the destination buffer. + /// The number of item to copy. + public unsafe void CopyTo(T* dstBuffer, int startDstIndex, int copyCount) + { + UnsafeUtility.MemCmp( dstBuffer + startDstIndex, m_BufferPtr, + UnsafeUtility.SizeOf() * copyCount); + } + + /// + /// Try to copy the list into another list. + /// + /// The destination of the copy. + /// + /// * true when the copy was performed. + /// * false when the copy was aborted because the destination have a capacity too small. + /// + public bool TryCopyTo(ListBuffer other) + { + if (other.Count + Count >= other.m_Capacity) + return false; + + UnsafeUtility.MemCmp( other.m_BufferPtr + other.Count, m_BufferPtr, UnsafeUtility.SizeOf() * Count); + *other.m_CountPtr += Count; + return true; + } + + /// + /// Try to copy the data from a buffer in this list. + /// + /// The pointer of the source memory to copy. + /// The number of item to copy from the source buffer. + /// + /// * true when the copy was performed. + /// * false when the copy was aborted because the capacity of this list is too small. + /// + public bool TryCopyFrom(T* srcPtr, int count) + { + if (count + Count > m_Capacity) + return false; + + UnsafeUtility.MemCmp( m_BufferPtr + Count, srcPtr, UnsafeUtility.SizeOf() * count); + *m_CountPtr += count; + return true; + } + } + + /// + /// Extensions for . + /// + public static class ListBufferExtensions + { + /// + /// Perform a quick sort on a . + /// + /// The list to sort. + /// The type of the element in the list. + public static void QuickSort(this ListBuffer self) + where T : unmanaged, IComparable + { + unsafe + { + CoreUnsafeUtils.QuickSort(self.Count, self.BufferPtr); + } + } + } +} diff --git a/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs.meta b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs.meta new file mode 100644 index 00000000000..1259d25752c --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 188d5dc897b64646b3757571725337ce +timeCreated: 1591792904 \ No newline at end of file diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs index a72d37ea47e..615e767ea64 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs @@ -119,6 +119,8 @@ IScriptableBakedReflectionSystemStageNotifier handle // a. If we have to remove a baked data // b. If we have to bake a probe // 4. Bake all required probes + // a. Bake probe that were added or modified + // b. Bake probe with a missing baked texture // 5. Remove unused baked data // 6. Update probe assets @@ -135,11 +137,31 @@ IScriptableBakedReflectionSystemStageNotifier handle // == 2. == var states = stackalloc HDProbeBakingState[bakedProbeCount]; + // A list of indices of probe we may want to force to rebake, even if the hashes matches. + // Usually, add a probe when something external to its state or the world state forces the bake. + var probeForcedToBakeIndices = stackalloc int[bakedProbeCount]; + var probeForcedToBakeIndicesCount = 0; + var probeForcedToBakeIndicesList = new ListBuffer( + probeForcedToBakeIndices, + &probeForcedToBakeIndicesCount, + bakedProbeCount + ); + ComputeProbeInstanceID(bakedProbes, states); ComputeProbeSettingsHashes(bakedProbes, states); // TODO: Handle bounce dependency here ComputeProbeBakingHashes(bakedProbeCount, allProbeDependencyHash, states); + // Force to rebake probe with missing baked texture + for (var i = 0; i < bakedProbeCount; ++i) + { + var instanceId = states[i].instanceID; + var probe = (HDProbe)EditorUtility.InstanceIDToObject(instanceId); + if (probe.bakedTexture != null && !probe.bakedTexture.Equals(null)) continue; + + probeForcedToBakeIndicesList.TryAdd(i); + } + CoreUnsafeUtils.QuickSort( bakedProbeCount, states ); @@ -173,7 +195,7 @@ IScriptableBakedReflectionSystemStageNotifier handle } } - if (operationCount > 0) + if (operationCount > 0 || probeForcedToBakeIndicesList.Count > 0) { // == 4. == var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize; @@ -185,33 +207,66 @@ IScriptableBakedReflectionSystemStageNotifier handle 0 ); - // Render probes - for (int i = 0; i < addCount; ++i) + // Compute indices of probes to bake: added, modified probe or with a missing baked texture. + var toBakeIndices = stackalloc int[bakedProbeCount]; + var toBakeIndicesCount = 0; + var toBakeIndicesList = new ListBuffer(toBakeIndices, &toBakeIndicesCount, bakedProbeCount); + { + // Note: we will add probes from change check and baked texture missing check. + // So we can add at most 2 time the probe in the list. + var toBakeIndicesTmp = stackalloc int[bakedProbeCount * 2]; + var toBakeIndicesTmpCount = 0; + var toBakeIndicesTmpList = + new ListBuffer(toBakeIndicesTmp, &toBakeIndicesTmpCount, bakedProbeCount * 2); + + // Add the indices from the added or modified detection check + toBakeIndicesTmpList.TryCopyFrom(addIndices, addCount); + // Add the probe with missing baked texture check + probeForcedToBakeIndicesList.TryCopyTo(toBakeIndicesTmpList); + + // Sort indices + toBakeIndicesTmpList.QuickSort(); + // Add to final list without the duplicates + var lastValue = int.MaxValue; + for (var i = 0; i < toBakeIndicesTmpList.Count; ++i) + { + if (lastValue == toBakeIndicesTmpList.GetUnchecked(i)) + // Skip duplicates + continue; + + lastValue = toBakeIndicesTmpList.GetUnchecked(i); + toBakeIndicesList.TryAdd(lastValue); + } + } + + // Render probes that were added or modified + for (int i = 0; i < toBakeIndicesList.Count; ++i) { handle.EnterStage( (int)BakingStages.ReflectionProbes, string.Format("Reflection Probes | {0} jobs", addCount), - i / (float)addCount + i / (float)toBakeIndicesCount ); - var index = addIndices[i]; + var index = toBakeIndicesList.GetUnchecked(i); var instanceId = states[index].instanceID; var probe = (HDProbe)EditorUtility.InstanceIDToObject(instanceId); var cacheFile = GetGICacheFileForHDProbe(states[index].probeBakingHash); - var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget((int)probe.resolution); // Get from cache or render the probe if (!File.Exists(cacheFile)) + { + var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget((int)probe.resolution); RenderAndWriteToFile(probe, cacheFile, cubeRT, planarRT); - - planarRT.Release(); + planarRT.Release(); + } } cubeRT.Release(); // Copy texture from cache - for (int i = 0; i < addCount; ++i) + for (int i = 0; i < toBakeIndicesList.Count; ++i) { - var index = addIndices[i]; + var index = toBakeIndicesList.GetUnchecked(i); var instanceId = states[index].instanceID; var probe = (HDProbe)EditorUtility.InstanceIDToObject(instanceId); var cacheFile = GetGICacheFileForHDProbe(states[index].probeBakingHash); @@ -246,9 +301,9 @@ IScriptableBakedReflectionSystemStageNotifier handle } // Import assets AssetDatabase.StartAssetEditing(); - for (int i = 0; i < addCount; ++i) + for (int i = 0; i < toBakeIndicesList.Count; ++i) { - var index = addIndices[i]; + var index = toBakeIndicesList.GetUnchecked(i); var instanceId = states[index].instanceID; var probe = (HDProbe)EditorUtility.InstanceIDToObject(instanceId); var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe); @@ -275,9 +330,9 @@ IScriptableBakedReflectionSystemStageNotifier handle targetBakedStates[targetI++] = m_HDProbeBakedStates[i]; } // Add new baked states - for (int i = 0; i < addCount; ++i) + for (int i = 0; i < toBakeIndicesList.Count; ++i) { - var state = states[addIndices[i]]; + var state = states[toBakeIndicesList.GetUnchecked(i)]; targetBakedStates[targetI++] = new HDProbeBakedState { instanceID = state.instanceID, From bfe3bb9ab4ee2d0f6279e36c255fdbc1905e53a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 10 Jun 2020 15:34:20 +0200 Subject: [PATCH 2/3] Updated changelog --- com.unity.render-pipelines.high-definition/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 69d1b936354..9a37af6e629 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -659,6 +659,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fixed white flash when enabling SSR or SSGI. - The ray traced indrect diffuse and RTGI were combined wrongly with the rest of the lighting (1254318). - Fixed an exception happening when using RTSSS without using RTShadows. +- Force to rebake probe with missing baked texture. (1253367) ### Changed - Improve MIP selection for decals on Transparents From 0c0a4eed8026216a1334602505b8efe184991649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 17 Jun 2020 11:08:35 +0200 Subject: [PATCH 3/3] Fix invalid memory copy and missing indice table replacement --- .../Runtime/Common/ListBuffer.cs | 6 +++--- .../Editor/Lighting/Reflection/HDBakedReflectionSystem.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs index 756f83cc66f..594313c44f8 100644 --- a/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs +++ b/com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs @@ -99,7 +99,7 @@ public bool TryAdd(in T value) /// The number of item to copy. public unsafe void CopyTo(T* dstBuffer, int startDstIndex, int copyCount) { - UnsafeUtility.MemCmp( dstBuffer + startDstIndex, m_BufferPtr, + UnsafeUtility.MemCpy( dstBuffer + startDstIndex, m_BufferPtr, UnsafeUtility.SizeOf() * copyCount); } @@ -116,7 +116,7 @@ public bool TryCopyTo(ListBuffer other) if (other.Count + Count >= other.m_Capacity) return false; - UnsafeUtility.MemCmp( other.m_BufferPtr + other.Count, m_BufferPtr, UnsafeUtility.SizeOf() * Count); + UnsafeUtility.MemCpy( other.m_BufferPtr + other.Count, m_BufferPtr, UnsafeUtility.SizeOf() * Count); *other.m_CountPtr += Count; return true; } @@ -135,7 +135,7 @@ public bool TryCopyFrom(T* srcPtr, int count) if (count + Count > m_Capacity) return false; - UnsafeUtility.MemCmp( m_BufferPtr + Count, srcPtr, UnsafeUtility.SizeOf() * count); + UnsafeUtility.MemCpy( m_BufferPtr + Count, srcPtr, UnsafeUtility.SizeOf() * count); *m_CountPtr += count; return true; } diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs index 615e767ea64..f173f379020 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Reflection/HDBakedReflectionSystem.cs @@ -290,7 +290,7 @@ IScriptableBakedReflectionSystemStageNotifier handle AssetDatabase.StartAssetEditing(); for (int i = 0; i < bakedProbeCount; ++i) { - var index = addIndices[i]; + var index = toBakeIndicesList.GetUnchecked(i); var instanceId = states[index].instanceID; var probe = (HDProbe)EditorUtility.InstanceIDToObject(instanceId); var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);