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 (labeling.enabled) { 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; } } else 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; } } }