using System; using Unity.Collections; using Unity.Entities; 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 /// 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; ushort m_DefaultValue = ushort.MaxValue; public LabelEntryMatchCache(IdLabelConfig idLabelConfig) { m_IdLabelConfig = idLabelConfig; m_InstanceIdToLabelEntryIndexLookup = new NativeList(k_StartingObjectCount, Allocator.Persistent); World.DefaultGameObjectInjectionWorld.GetOrCreateSystem().Activate(this); } public bool TryGetLabelEntryFromInstanceId(uint instanceId, out IdLabelEntry labelEntry, out int index) { labelEntry = default; index = -1; if (m_InstanceIdToLabelEntryIndexLookup.Length <= instanceId || m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] == m_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 < m_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 (int i = oldLength; i < instanceId; i++) m_InstanceIdToLabelEntryIndexLookup[i] = m_DefaultValue; } m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = (ushort)index; } else if (m_InstanceIdToLabelEntryIndexLookup.Length > (int)instanceId) { m_InstanceIdToLabelEntryIndexLookup[(int)instanceId] = m_DefaultValue; } } public void Dispose() { World.DefaultGameObjectInjectionWorld?.GetExistingSystem()?.Deactivate(this); m_InstanceIdToLabelEntryIndexLookup.Dispose(); } public void ClearCache() { m_InstanceIdToLabelEntryIndexLookup.Clear(); } } }