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
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);
|
|
}
|
|
}
|
|
}
|