// Decompiled with JetBrains decompiler // Type: Microsoft.Iris.Render.Protocol.HandleGroup // Assembly: UIX.RenderApi, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217 // MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1 // Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll using Microsoft.Iris.Render.Common; using System; using System.Collections; using System.Runtime.InteropServices; namespace Microsoft.Iris.Render.Protocol { internal class HandleGroup : RenderObject, IDisposable, IEnumerable, IRenderHandleOwner { private const int USAGE_INDEX_SHIFT = 5; private const uint USAGE_INDEX_MASK = 31; private const uint USAGE_SLOT_COUNT = 32; private const uint USAGE_FULL_MASK = 4294967295; private const uint LOWEST_BIT = 1; private const uint INITIAL_BSEARCH_SPLIT = 16; private const uint INITIAL_BSEARCH_TEST = 65535; private static GCHandle s_gchEmpty = new GCHandle(); private RenderPort m_portOwner; private GCHandleType m_ht; private GCHandle[] m_objects; private uint[] m_usage; private byte[] m_uniqueness; private uint m_alloc; private uint m_used; private uint m_hint; private uint m_maxObjects; public HandleGroup(GCHandleType ht, RenderPort portOwner) : this(ht, portOwner, false, uint.MaxValue) { } public HandleGroup(GCHandleType ht, RenderPort portOwner, bool uniquify) : this(ht, portOwner, uniquify, uint.MaxValue) { } public HandleGroup(GCHandleType ht, RenderPort portOwner, uint maxObjects) : this(ht, portOwner, false, maxObjects) { } public HandleGroup(GCHandleType ht, RenderPort portOwner, bool uniquify, uint maxObjects) { Debug2.Validate(portOwner != null, typeof (ArgumentNullException), (object) nameof (portOwner), (object) "Must specify valid owner"); this.m_ht = ht; this.m_portOwner = portOwner; this.m_maxObjects = maxObjects; if (!uniquify) return; this.m_uniqueness = new byte[1]; } protected override void Dispose(bool inDispose) { try { this.Clear(); } finally { base.Dispose(inDispose); } } RENDERHANDLE IRenderHandleOwner.RenderHandle => RENDERHANDLE.NULL; void IRenderHandleOwner.OnDisconnect() { } public IRenderHandleOwner this[uint index] { get { this.ValidateSlot(index); GCHandle gcHandle = this.m_objects[(IntPtr) index]; return !gcHandle.IsAllocated ? (IRenderHandleOwner) null : (IRenderHandleOwner) gcHandle.Target; } set { this.ValidateSlot(index); this.SetIndex(index, value); } } public uint Count => this.m_alloc; public IEnumerator GetEnumerator() => new HandleGroup.ObjectCopy(this).GetEnumerator(); public IRenderHandleOwner Get( uint index, uint expectedUniqueness, bool fAllowInvalid) { if (!this.ValidateAccess(index, expectedUniqueness, fAllowInvalid)) return (IRenderHandleOwner) null; GCHandle gcHandle = this.m_objects[(IntPtr) index]; return !gcHandle.IsAllocated ? (IRenderHandleOwner) null : (IRenderHandleOwner) gcHandle.Target; } public IRenderHandleOwner Get(uint index, uint expectedUniqueness) => this.Get(index, expectedUniqueness, false); public void Set(uint index, uint expectedUniqueness, IRenderHandleOwner owner) { this.ValidateAccess(index, expectedUniqueness); this.SetIndex(index, owner); } public void Clear() { if (this.m_objects == null) return; for (uint index = 0; (long) index < (long) this.m_objects.Length; ++index) this.SetIndex(index, (IRenderHandleOwner) null); this.m_objects = (GCHandle[]) null; this.m_usage = (uint[]) null; if (this.m_uniqueness != null) this.m_uniqueness = new byte[1]; this.m_alloc = 0U; this.m_used = 0U; this.m_hint = 0U; } public uint Add(IRenderHandleOwner owner) => this.Add(owner, out uint _); public uint Add(IRenderHandleOwner owner, out uint unique) { if (this.m_used >= this.m_alloc) this.GrowStorage(); uint index = this.AllocSlot(); this.SetIndex(index, owner); this.UpdateUniqueness(index, out unique); return index; } public void AddAtIndex(IRenderHandleOwner owner, uint index) => this.AddAtIndex(owner, index, out uint _); public void AddAtIndex(IRenderHandleOwner owner, uint index, out uint unique) { if (index >= this.m_alloc) this.GrowStorageTo(index + 1U); this.AllocSlotAt(index); this.SetIndex(index, owner); this.UpdateUniqueness(index, out unique); } public void AddAtIndexWithKnownUniqueness( IRenderHandleOwner owner, uint index, uint unique, bool fUpdateExisting) { if (index >= this.m_alloc) this.GrowStorageTo(index + 1U); if (fUpdateExisting && !this.ValidateSlotFree(index, true)) Debug2.Validate(this.Get(index, unique) == null, typeof (ArgumentException), "Should only be updating a null owner"); else this.AllocSlotAt(index); this.SetIndex(index, owner); this.SetUniqueness(index, unique); } public void Remove(uint index) { this.ValidateSlot(index); this.SetIndex(index, (IRenderHandleOwner) null); this.FreeSlot(index); } public void Remove(uint index, uint expectedUniqueness) { this.ValidateAccess(index, expectedUniqueness); this.SetIndex(index, (IRenderHandleOwner) null); this.FreeSlot(index); } private static bool IsEmpty(GCHandle gch) => GCHandle.ToIntPtr(gch) == IntPtr.Zero; private void SetIndex(uint index, IRenderHandleOwner newOwner) { GCHandle gch = this.m_objects[(IntPtr) index]; if (!HandleGroup.IsEmpty(gch)) { ((IRenderHandleOwner) gch.Target)?.OnDisconnect(); gch.Free(); } if (newOwner != null) this.m_objects[(IntPtr) index] = GCHandle.Alloc((object) newOwner, this.m_ht); else this.m_objects[(IntPtr) index] = HandleGroup.s_gchEmpty; } private void UpdateUniqueness(uint index, out uint unique) { byte num1 = 0; if (this.m_uniqueness != null) { byte num2 = this.m_uniqueness[(IntPtr) index]; num1 = num2 >= byte.MaxValue ? (byte) 1 : (byte) ((uint) num2 + 1U); this.m_uniqueness[(IntPtr) index] = num1; } unique = (uint) num1; } private void SetUniqueness(uint index, uint unique) { Debug2.Validate(unique <= (uint) byte.MaxValue, typeof (ArgumentOutOfRangeException), "Uniqueness must be a byte"); if (this.m_uniqueness == null) return; this.m_uniqueness[(IntPtr) index] = (byte) (unique & (uint) byte.MaxValue); } private void ValidateSlot(uint index) => this.ValidateSlot(index, false); private bool ValidateSlot(uint index, bool fAllowInvalid) { bool flag = false; if (index < this.m_alloc && ((int) this.m_usage[(IntPtr) (index >> 5)] & 1 << (int) index) != 0) flag = true; Debug2.Throw(flag || fAllowInvalid, "Slot is not allocated"); return flag; } private void ValidateSlotFree(uint index) => this.ValidateSlotFree(index, false); private bool ValidateSlotFree(uint index, bool fAllowInvalid) { bool flag = false; if (index < this.m_alloc && ((int) this.m_usage[(IntPtr) (index >> 5)] & 1 << (int) index) == 0) flag = true; Debug2.Throw(flag || fAllowInvalid, "Slot is not free"); return flag; } private void ValidateAccess(uint index, uint expectedUniqueness) => this.ValidateAccess(index, expectedUniqueness, false); private bool ValidateAccess(uint index, uint expectedUniqueness, bool fAllowInvalid) { if (!this.ValidateSlot(index, fAllowInvalid)) return false; uint num = 0; if (this.m_uniqueness != null) num = (uint) this.m_uniqueness[(IntPtr) index]; bool flag = (int) expectedUniqueness == (int) num; Debug2.Throw(flag || fAllowInvalid, "Slot uniqueness is stale"); return flag; } private uint AllocSlot() { uint num1 = 0; uint hint; for (hint = this.m_hint; (long) hint < (long) this.m_usage.Length; ++hint) { num1 = this.m_usage[(IntPtr) hint]; if (num1 != uint.MaxValue) break; } this.m_hint = hint; uint num2 = 16; uint maxValue = (uint) ushort.MaxValue; uint num3 = 0; do { if (((int) num1 & (int) maxValue) == (int) maxValue) { num1 >>= (int) num2; num3 += num2; } num2 >>= 1; maxValue >>= (int) num2; } while (num2 != 0U); this.m_usage[(IntPtr) hint] |= 1U << (int) num3; ++this.m_used; return hint << 5 | num3; } private void AllocSlotAt(uint index) { this.ValidateSlotFree(index); this.m_usage[(IntPtr) (index >> 5)] |= 1U << (int) index; ++this.m_used; } private void FreeSlot(uint index) { uint num = index >> 5; this.m_usage[(IntPtr) num] &= (uint) ~(1 << (int) index); --this.m_used; if (this.m_hint <= num) return; this.m_hint = num; } private void GrowStorage() { Debug2.Validate(this.m_alloc < this.m_maxObjects, typeof (InvalidOperationException), "Too many video resources have been allocated"); uint newSize = this.m_alloc * 2U; if (newSize == 0U) newSize = 32U; if (newSize > this.m_maxObjects) newSize = this.m_maxObjects; this.GrowStorageTo(newSize); } private void GrowStorageTo(uint newSize) { Debug2.Validate(newSize > this.m_alloc, typeof (ArgumentException), nameof (newSize)); Debug2.Validate(newSize <= this.m_maxObjects, typeof (InvalidOperationException), "Too many video resources have been allocated"); GCHandle[] gcHandleArray = new GCHandle[(IntPtr) newSize]; uint[] numArray1 = (uint[]) null; byte[] numArray2 = (byte[]) null; uint num = (uint) ((int) newSize + 32 - 1) >> 5; if (this.m_usage == null || (long) this.m_usage.Length < (long) num) numArray1 = new uint[(IntPtr) num]; if (this.m_uniqueness != null) { numArray2 = new byte[(IntPtr) newSize]; Array.Copy((Array) this.m_uniqueness, (Array) numArray2, this.m_uniqueness.Length); } if (this.m_objects != null) { Array.Copy((Array) this.m_objects, (Array) gcHandleArray, this.m_objects.Length); if (numArray1 != null) Array.Copy((Array) this.m_usage, (Array) numArray1, this.m_usage.Length); this.m_hint = (uint) this.m_usage.Length; } this.m_objects = gcHandleArray; if (numArray1 != null) this.m_usage = numArray1; this.m_uniqueness = numArray2; this.m_alloc = newSize; } private class ObjectCopy { private IRenderHandleOwner[] m_arObjects; public ObjectCopy(HandleGroup map) { uint used = map.m_used; this.m_arObjects = new IRenderHandleOwner[(IntPtr) used]; uint num = 0; for (uint index = 0; index < used; ++index) { GCHandle gch = map.m_objects[(IntPtr) index]; if (!HandleGroup.IsEmpty(gch)) { IRenderHandleOwner target = (IRenderHandleOwner) gch.Target; if (target != null) this.m_arObjects[(IntPtr) num++] = target; } } } public IEnumerator GetEnumerator() => this.m_arObjects.GetEnumerator(); } } }