using System;
using Unity.Collections;
namespace UnityEngine.Perception.GroundTruth
{
///
/// Cache of instance id -> label entry index for a LabelConfig. This is not well optimized and is the source of
/// a known memory leak for apps that create new instances frequently.
///
public class LabelEntryMatchCache : IGroundTruthGenerator, IDisposable
{
// The initial size of the cache. Large enough to avoid resizing small lists multiple times
const int k_StartingObjectCount = 1 << 8;
NativeList m_InstanceIdToLabelEntryIndexLookup;
IdLabelConfig m_IdLabelConfig;
private bool m_ReceiveUpdates;
const ushort k_DefaultValue = ushort.MaxValue;
internal LabelEntryMatchCache(IdLabelConfig idLabelConfig, Allocator allocator = Allocator.Persistent, bool receiveUpdates = true)
{
m_IdLabelConfig = idLabelConfig;
m_InstanceIdToLabelEntryIndexLookup = new NativeList(k_StartingObjectCount, allocator);
m_ReceiveUpdates = receiveUpdates;
if (receiveUpdates)
LabelManager.singleton.Activate(this);
}
private LabelEntryMatchCache(LabelEntryMatchCache labelEntryMatchCache, Allocator allocator)
{
m_IdLabelConfig = labelEntryMatchCache.m_IdLabelConfig;
m_InstanceIdToLabelEntryIndexLookup = new NativeList(labelEntryMatchCache.m_InstanceIdToLabelEntryIndexLookup.Length, allocator);
m_InstanceIdToLabelEntryIndexLookup.AddRange(labelEntryMatchCache.m_InstanceIdToLabelEntryIndexLookup.AsArray());
m_ReceiveUpdates = false;
}
///
/// Retrieves the label entry for the given instance id.
///
/// The instance id to look up
/// The of the match if found. Otherwise returns default(IdlabelEntry)
.
/// The index of the matched in the if found. Otherwise returns -1.
/// True if a the instance id was found in the cache.
public bool TryGetLabelEntryFromInstanceId(uint instanceId, out IdLabelEntry labelEntry, out int index)
{
labelEntry = default;
index = -1;
if (m_InstanceIdToLabelEntryIndexLookup.Length <= instanceId || m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] == k_DefaultValue)
return false;
index = m_InstanceIdToLabelEntryIndexLookup[(int)instanceId];
labelEntry = m_IdLabelConfig.labelEntries[index];
return true;
}
///
void IGroundTruthGenerator.SetupMaterialProperties(MaterialPropertyBlock mpb, Renderer renderer, Labeling labeling, uint instanceId)
{
if (m_IdLabelConfig.TryGetMatchingConfigurationEntry(labeling, out _, out var index))
{
Debug.Assert(index < k_DefaultValue, "Too many entries in the label config");
if (m_InstanceIdToLabelEntryIndexLookup.Length <= instanceId)
{
var oldLength = m_InstanceIdToLabelEntryIndexLookup.Length;
m_InstanceIdToLabelEntryIndexLookup.Resize((int)instanceId + 1, NativeArrayOptions.ClearMemory);
for (var i = oldLength; i < instanceId; i++)
m_InstanceIdToLabelEntryIndexLookup[i] = k_DefaultValue;
}
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = (ushort)index;
}
else if (m_InstanceIdToLabelEntryIndexLookup.Length > instanceId)
{
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = k_DefaultValue;
}
}
///
void IGroundTruthGenerator.ClearMaterialProperties(MaterialPropertyBlock mpb, Renderer renderer, Labeling labeling, uint instanceId)
{
if (m_InstanceIdToLabelEntryIndexLookup.Length > instanceId)
{
m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = k_DefaultValue;
}
}
///
public void Dispose()
{
if (m_ReceiveUpdates)
LabelManager.singleton.Deactivate(this);
m_InstanceIdToLabelEntryIndexLookup.Dispose();
}
internal LabelEntryMatchCache CloneCurrentState(Allocator allocator)
{
var clone = new LabelEntryMatchCache(this, Allocator.Persistent);
return clone;
}
}
}