You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

178 lines
7.1 KiB

using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using UnityEngine.Assertions;
namespace UnityEngine.Rendering
{
//@ Add instance version to detect dangling instance handles.
internal struct InstanceHandle : IEquatable<InstanceHandle>, IComparable<InstanceHandle>
{
// Don't use this index to reference GPU data. This index is to reference CPU data only.
// To reference GPU data convert InstahceHandle to GPUInstanceIndex.
public int index { get; private set; }
// This is unique instance index for each instance type.
public int instanceIndex => index >> InstanceTypeInfo.kInstanceTypeBitCount;
// We store type bits as lower bits because this makes max InstanceHandle index bounded by how many instances we have.
// So you can allocate directly indexed arrays. This is fine as long as we have only 1 to 4 instance types.
// If we put type bits in higher bits then we might want to make CPUInstanceData sparse set InstanceIndices table to be paged.
public InstanceType type => (InstanceType)(index & InstanceTypeInfo.kInstanceTypeMask);
public bool valid => index != -1;
public static readonly InstanceHandle Invalid = new InstanceHandle() { index = -1 };
public static InstanceHandle Create(int instanceIndex, InstanceType instanceType) { return new InstanceHandle() { index = instanceIndex << InstanceTypeInfo.kInstanceTypeBitCount | (int)instanceType }; }
public static InstanceHandle FromInt(int value) { return new InstanceHandle() { index = value }; }
public bool Equals(InstanceHandle other) => index == other.index;
public int CompareTo(InstanceHandle other) { return index.CompareTo(other.index); }
public override int GetHashCode() { return index; }
}
internal struct SharedInstanceHandle : IEquatable<SharedInstanceHandle>, IComparable<SharedInstanceHandle>
{
public int index { get; set; }
public bool valid => index != -1;
public static readonly SharedInstanceHandle Invalid = new SharedInstanceHandle() { index = -1 };
public bool Equals(SharedInstanceHandle other) => index == other.index;
public int CompareTo(SharedInstanceHandle other) { return index.CompareTo(other.index); }
public override int GetHashCode() { return index; }
}
internal struct GPUInstanceIndex : IEquatable<GPUInstanceIndex>, IComparable<GPUInstanceIndex>
{
public int index { get; set; }
public bool valid => index != -1;
public static readonly GPUInstanceIndex Invalid = new GPUInstanceIndex() { index = -1 };
public bool Equals(GPUInstanceIndex other) => index == other.index;
public int CompareTo(GPUInstanceIndex other) { return index.CompareTo(other.index); }
public override int GetHashCode() { return index; }
}
internal struct InstanceAllocator
{
private NativeArray<int> m_StructData;
private NativeList<int> m_FreeInstances;
private int m_BaseInstanceOffset;
private int m_InstanceStride;
public int length { get => m_StructData[0]; set => m_StructData[0] = value; }
public bool valid => m_StructData.IsCreated;
public void Initialize(int baseInstanceOffset = 0, int instanceStride = 1)
{
m_StructData = new NativeArray<int>(1, Allocator.Persistent);
m_FreeInstances = new NativeList<int>(Allocator.Persistent);
m_BaseInstanceOffset = baseInstanceOffset;
m_InstanceStride = instanceStride;
}
public void Dispose()
{
m_StructData.Dispose();
m_FreeInstances.Dispose();
}
public int AllocateInstance()
{
int instance;
if (m_FreeInstances.Length > 0)
{
instance = m_FreeInstances[m_FreeInstances.Length - 1];
m_FreeInstances.RemoveAtSwapBack(m_FreeInstances.Length - 1);
}
else
{
instance = length * m_InstanceStride + m_BaseInstanceOffset;
length += 1;
}
return instance;
}
public void FreeInstance(int instance)
{
//@ This is a bit weak validation. Need something better but fast.
Assert.IsTrue(instance >= 0 && instance < length * m_InstanceStride);
m_FreeInstances.Add(instance);
}
public int GetNumAllocated()
{
return length - m_FreeInstances.Length;
}
}
internal unsafe struct InstanceAllocators
{
private InstanceAllocator m_InstanceAlloc_MeshRenderer;
private InstanceAllocator m_InstanceAlloc_SpeedTree;
private InstanceAllocator m_SharedInstanceAlloc;
public void Initialize()
{
//@ Will keep it as two separate allocators for two types for now. Nested native containers are not allowed in burst.
m_InstanceAlloc_MeshRenderer = new InstanceAllocator();
m_InstanceAlloc_SpeedTree = new InstanceAllocator();
m_InstanceAlloc_MeshRenderer.Initialize((int)InstanceType.MeshRenderer, InstanceTypeInfo.kMaxInstanceTypesCount);
m_InstanceAlloc_SpeedTree.Initialize((int)InstanceType.SpeedTree, InstanceTypeInfo.kMaxInstanceTypesCount);
m_SharedInstanceAlloc = new InstanceAllocator();
m_SharedInstanceAlloc.Initialize();
}
public unsafe void Dispose()
{
m_InstanceAlloc_MeshRenderer.Dispose();
m_InstanceAlloc_SpeedTree.Dispose();
m_SharedInstanceAlloc.Dispose();
}
private InstanceAllocator GetInstanceAllocator(InstanceType type)
{
switch (type)
{
case InstanceType.MeshRenderer:
return m_InstanceAlloc_MeshRenderer;
case InstanceType.SpeedTree:
return m_InstanceAlloc_SpeedTree;
default:
throw new ArgumentException("Allocator for this type is not created.");
}
}
public int GetInstanceHandlesLength(InstanceType type)
{
return GetInstanceAllocator(type).length;
}
public int GetInstancesLength(InstanceType type)
{
return GetInstanceAllocator(type).GetNumAllocated();
}
public InstanceHandle AllocateInstance(InstanceType type)
{
return InstanceHandle.FromInt(GetInstanceAllocator(type).AllocateInstance());
}
public void FreeInstance(InstanceHandle instance)
{
Assert.IsTrue(instance.valid);
GetInstanceAllocator(instance.type).FreeInstance(instance.index);
}
public unsafe SharedInstanceHandle AllocateSharedInstance()
{
return new SharedInstanceHandle { index = m_SharedInstanceAlloc.AllocateInstance() };
}
public void FreeSharedInstance(SharedInstanceHandle instance)
{
Assert.IsTrue(instance.valid);
m_SharedInstanceAlloc.FreeInstance(instance.index);
}
}
}