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..594313c44f8
--- /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.MemCpy( 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.MemCpy( 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.MemCpy( 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/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index f29fc7bf234..13ec4f22be2 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -695,6 +695,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed an issue where manipulating the color wheels in a volume component would reset the cursor every time.
- Fixed an issue where static sky lighting would not be updated for a new scene until it's reloaded at least once.
- Fixed culling for decals when used in prefabs and edited in context.
+- Force to rebake probe with missing baked texture. (1253367)
### Changed
- Improve MIP selection for decals on Transparents
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..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
@@ -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);
@@ -235,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);
@@ -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,