284 lines
9.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|