Skip to content

Fixed 1253367 by rebaking probe with missing baked texture. #818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions com.unity.render-pipelines.core/Runtime/Common/ListBuffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using Unity.Collections.LowLevel.Unsafe;

namespace UnityEngine.Rendering
{
/// <summary>
/// A list that stores value on a provided memory buffer.
///
/// Usually use this to have a list on stack allocated memory.
/// </summary>
/// <typeparam name="T">The type of the data stored in the list.</typeparam>
public unsafe struct ListBuffer<T>
where T: unmanaged
{
private T* m_BufferPtr;
private int m_Capacity;
private int* m_CountPtr;

/// <summary>
/// The pointer to the memory storage.
/// </summary>
internal T* BufferPtr => m_BufferPtr;

/// <summary>
/// The number of item in the list.
/// </summary>
public int Count => *m_CountPtr;

/// <summary>
/// The maximum number of item stored in this list.
/// </summary>
public int Capacity => m_Capacity;

/// <summary>
/// Instantiate a new list.
/// </summary>
/// <param name="bufferPtr">The address in memory to store the data.</param>
/// <param name="countPtr">The address in memory to store the number of item of this list..</param>
/// <param name="capacity">The number of <typeparamref name="T"/> that can be stored in the buffer.</param>
public ListBuffer(T* bufferPtr, int* countPtr, int capacity)
{
m_BufferPtr = bufferPtr;
m_Capacity = capacity;
m_CountPtr = countPtr;
}

/// <summary>
/// Get an item from the list.
/// </summary>
/// <param name="index">The index of the item to get.</param>
/// <returns>A reference to the item.</returns>
/// <exception cref="IndexOutOfRangeException">If the index is invalid.</exception>
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];
}
}

/// <summary>
/// Get an item from the list.
///
/// Safety: index must be inside the bounds of the list.
/// </summary>
/// <param name="index">The index of the item to get.</param>
/// <returns>A reference to the item.</returns>
public unsafe ref T GetUnchecked(in int index) => ref m_BufferPtr[index];

/// <summary>
/// Try to add a value in the list.
/// </summary>
/// <param name="value">A reference to the value to add.</param>
/// <returns>
/// <code>true</code> when the value was added,
/// <code>false</code> when the value was not added because the capacity was reached.
/// </returns>
public bool TryAdd(in T value)
{
if (Count >= m_Capacity)
return false;

m_BufferPtr[Count] = value;
++*m_CountPtr;
return true;
}

/// <summary>
/// Copy the content of this list into another buffer in memory.
///
/// Safety:
/// * The destination must have enough memory to receive the copied data.
/// </summary>
/// <param name="dstBuffer">The destination buffer of the copy operation.</param>
/// <param name="startDstIndex">The index of the first element that will be copied in the destination buffer.</param>
/// <param name="copyCount">The number of item to copy.</param>
public unsafe void CopyTo(T* dstBuffer, int startDstIndex, int copyCount)
{
UnsafeUtility.MemCpy( dstBuffer + startDstIndex, m_BufferPtr,
UnsafeUtility.SizeOf<T>() * copyCount);
}

/// <summary>
/// Try to copy the list into another list.
/// </summary>
/// <param name="other">The destination of the copy.</param>
/// <returns>
/// * <code>true</code> when the copy was performed.
/// * <code>false</code> when the copy was aborted because the destination have a capacity too small.
/// </returns>
public bool TryCopyTo(ListBuffer<T> other)
{
if (other.Count + Count >= other.m_Capacity)
return false;

UnsafeUtility.MemCpy( other.m_BufferPtr + other.Count, m_BufferPtr, UnsafeUtility.SizeOf<T>() * Count);
*other.m_CountPtr += Count;
return true;
}

/// <summary>
/// Try to copy the data from a buffer in this list.
/// </summary>
/// <param name="srcPtr">The pointer of the source memory to copy.</param>
/// <param name="count">The number of item to copy from the source buffer.</param>
/// <returns>
/// * <code>true</code> when the copy was performed.
/// * <code>false</code> when the copy was aborted because the capacity of this list is too small.
/// </returns>
public bool TryCopyFrom(T* srcPtr, int count)
{
if (count + Count > m_Capacity)
return false;

UnsafeUtility.MemCpy( m_BufferPtr + Count, srcPtr, UnsafeUtility.SizeOf<T>() * count);
*m_CountPtr += count;
return true;
}
}

/// <summary>
/// Extensions for <see cref="ListBuffer{T}"/>.
/// </summary>
public static class ListBufferExtensions
{
/// <summary>
/// Perform a quick sort on a <see cref="ListBuffer{T}"/>.
/// </summary>
/// <param name="self">The list to sort.</param>
/// <typeparam name="T">The type of the element in the list.</typeparam>
public static void QuickSort<T>(this ListBuffer<T> self)
where T : unmanaged, IComparable<T>
{
unsafe
{
CoreUnsafeUtils.QuickSort<int>(self.Count, self.BufferPtr);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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<int>(
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<HDProbeBakingState, Hash128, HDProbeBakingState.ProbeBakingHash>(
bakedProbeCount, states
);
Expand Down Expand Up @@ -173,7 +195,7 @@ IScriptableBakedReflectionSystemStageNotifier handle
}
}

if (operationCount > 0)
if (operationCount > 0 || probeForcedToBakeIndicesList.Count > 0)
{
// == 4. ==
var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
Expand All @@ -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<int>(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<int>(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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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,
Expand Down