mirror of
https://github.com/ZuneDev/Xune.git
synced 2026-07-27 13:13:10 -07:00
368 lines
13 KiB
C#
368 lines
13 KiB
C#
// 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();
|
|
}
|
|
}
|
|
}
|