Files
XCEngine/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererDataCollection.cs

284 lines
9.5 KiB
C#

using System;
using System.Runtime.CompilerServices;
namespace XCEngine.Rendering.Universal
{
internal sealed class ScriptableRendererDataCollection
{
private ScriptableRendererData[] m_rendererDataList;
public ScriptableRendererDataCollection()
{
m_rendererDataList =
Array.Empty<ScriptableRendererData>();
}
public ScriptableRendererData GetDefaultRendererData(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
return GetRendererData(
ref configuredRendererDataList,
ref defaultRendererIndex,
ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData),
createDefaultRendererData);
}
public ScriptableRendererData GetRendererData(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
int rendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
int resolvedRendererIndex =
ResolveRendererIndexWithFallback(
ref configuredRendererDataList,
ref defaultRendererIndex,
rendererIndex,
createDefaultRendererData);
if (resolvedRendererIndex < 0)
{
return null;
}
return m_rendererDataList[resolvedRendererIndex];
}
public int ResolveDefaultRendererIndex(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
if (rendererDataList.Length == 0)
{
return -1;
}
if (defaultRendererIndex < 0 ||
defaultRendererIndex >= rendererDataList.Length)
{
defaultRendererIndex = 0;
}
if (rendererDataList[defaultRendererIndex] != null)
{
return defaultRendererIndex;
}
int firstValidRendererIndex =
FindFirstValidRendererIndex(rendererDataList);
if (firstValidRendererIndex >= 0)
{
defaultRendererIndex = firstValidRendererIndex;
return defaultRendererIndex;
}
rendererDataList[defaultRendererIndex] =
createDefaultRendererData != null
? createDefaultRendererData()
: null;
return rendererDataList[defaultRendererIndex] != null
? defaultRendererIndex
: -1;
}
public int ResolveRendererIndexWithFallback(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
int rendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
if (rendererDataList.Length == 0)
{
return -1;
}
if (rendererIndex < 0 ||
rendererIndex >= rendererDataList.Length)
{
return ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
}
if (rendererDataList[rendererIndex] == null)
{
return ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
}
return rendererIndex;
}
public void Synchronize(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
ref int collectionHash,
ref bool collectionHashResolved,
Func<ScriptableRendererData> createDefaultRendererData,
Action onChanged)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
int resolvedDefaultRendererIndex =
ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
int resolvedHash =
ComputeCollectionHash(
rendererDataList,
resolvedDefaultRendererIndex);
if (!collectionHashResolved)
{
collectionHash = resolvedHash;
collectionHashResolved = true;
return;
}
if (resolvedHash == collectionHash)
{
return;
}
collectionHash = resolvedHash;
onChanged?.Invoke();
}
public void ReleaseRuntimeResources(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData == null ||
WasRendererDataReleasedEarlier(
rendererDataList,
i))
{
continue;
}
rendererData.ReleaseRuntimeResourcesInstance();
}
}
private ScriptableRendererData[] ResolveConfiguredRendererDataList(
ref ScriptableRendererData[] configuredRendererDataList,
Func<ScriptableRendererData> createDefaultRendererData)
{
if (configuredRendererDataList == null ||
configuredRendererDataList.Length == 0)
{
ScriptableRendererData defaultRendererData =
createDefaultRendererData != null
? createDefaultRendererData()
: null;
configuredRendererDataList =
defaultRendererData != null
? new ScriptableRendererData[]
{
defaultRendererData
}
: Array.Empty<ScriptableRendererData>();
}
m_rendererDataList = configuredRendererDataList;
return m_rendererDataList;
}
private static int ComputeCollectionHash(
ScriptableRendererData[] rendererDataList,
int defaultRendererIndex)
{
unchecked
{
int hash = 17;
hash = (hash * 31) + defaultRendererIndex;
if (rendererDataList == null)
{
return hash;
}
hash = (hash * 31) + rendererDataList.Length;
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData == null)
{
hash = (hash * 31) + 1;
continue;
}
hash =
(hash * 31) +
RuntimeHelpers.GetHashCode(rendererData);
hash =
(hash * 31) +
rendererData.GetRuntimeStateVersionInstance();
}
return hash;
}
}
private static int FindFirstValidRendererIndex(
ScriptableRendererData[] rendererDataList)
{
for (int i = 0; i < rendererDataList.Length; ++i)
{
if (rendererDataList[i] != null)
{
return i;
}
}
return -1;
}
private static bool WasRendererDataReleasedEarlier(
ScriptableRendererData[] rendererDataList,
int rendererDataIndex)
{
ScriptableRendererData rendererData =
rendererDataList[rendererDataIndex];
for (int i = 0; i < rendererDataIndex; ++i)
{
if (object.ReferenceEquals(
rendererDataList[i],
rendererData))
{
return true;
}
}
return false;
}
}
}