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.
174 lines
5.2 KiB
174 lines
5.2 KiB
using System;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Jobs;
|
|
|
|
namespace UnityEngine.Rendering
|
|
{
|
|
internal struct ParallelBitArray
|
|
{
|
|
private Allocator m_Allocator;
|
|
private NativeArray<long> m_Bits;
|
|
private int m_Length;
|
|
|
|
public int Length => m_Length;
|
|
|
|
public bool IsCreated
|
|
{
|
|
get { return m_Bits.IsCreated; }
|
|
}
|
|
|
|
public ParallelBitArray(int length, Allocator allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
|
|
{
|
|
m_Allocator = allocator;
|
|
m_Bits = new NativeArray<long>((length + 63) / 64, allocator, options);
|
|
m_Length = length;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
m_Bits.Dispose();
|
|
m_Length = 0;
|
|
}
|
|
|
|
public void Dispose(JobHandle inputDeps)
|
|
{
|
|
m_Bits.Dispose(inputDeps);
|
|
m_Length = 0;
|
|
}
|
|
|
|
public void Resize(int newLength)
|
|
{
|
|
int oldLength = m_Length;
|
|
if (newLength == oldLength)
|
|
return;
|
|
|
|
int oldBitsLength = m_Bits.Length;
|
|
int newBitsLength = (newLength + 63) / 64;
|
|
if (newBitsLength != oldBitsLength)
|
|
{
|
|
var newBits = new NativeArray<long>(newBitsLength, m_Allocator, NativeArrayOptions.UninitializedMemory);
|
|
if (m_Bits.IsCreated)
|
|
{
|
|
NativeArray<long>.Copy(m_Bits, newBits, m_Bits.Length);
|
|
m_Bits.Dispose();
|
|
}
|
|
m_Bits = newBits;
|
|
}
|
|
|
|
// mask off bits past the length
|
|
int validLength = Math.Min(oldLength, newLength);
|
|
int validBitsLength = Math.Min(oldBitsLength, newBitsLength);
|
|
for (int chunkIndex = validBitsLength; chunkIndex < m_Bits.Length; ++chunkIndex)
|
|
{
|
|
int validBitCount = Math.Max(validLength - 64 * chunkIndex, 0);
|
|
if (validBitCount < 64)
|
|
{
|
|
ulong validMask = (1ul << validBitCount) - 1;
|
|
m_Bits[chunkIndex] &= (long)validMask;
|
|
}
|
|
}
|
|
m_Length = newLength;
|
|
}
|
|
|
|
public void Set(int index, bool value)
|
|
{
|
|
unsafe
|
|
{
|
|
Debug.Assert(0 <= index && index < m_Length);
|
|
|
|
int entry_index = index >> 6;
|
|
long* entries = (long*)m_Bits.GetUnsafePtr();
|
|
|
|
ulong bit = 1ul << (index & 0x3f);
|
|
long and_mask = (long)(~bit);
|
|
long or_mask = value ? (long)bit : 0;
|
|
|
|
long old_entry, new_entry;
|
|
do
|
|
{
|
|
old_entry = Interlocked.Read(ref entries[entry_index]);
|
|
new_entry = (old_entry & and_mask) | or_mask;
|
|
} while (Interlocked.CompareExchange(ref entries[entry_index], new_entry, old_entry) != old_entry);
|
|
}
|
|
}
|
|
|
|
public bool Get(int index)
|
|
{
|
|
unsafe
|
|
{
|
|
Debug.Assert(0 <= index && index < m_Length);
|
|
|
|
int entry_index = index >> 6;
|
|
long* entries = (long*)m_Bits.GetUnsafeReadOnlyPtr();
|
|
|
|
ulong bit = 1ul << (index & 0x3f);
|
|
long check_mask = (long)bit;
|
|
return (entries[entry_index] & check_mask) != 0;
|
|
}
|
|
}
|
|
|
|
public ulong GetChunk(int chunk_index)
|
|
{
|
|
return (ulong)m_Bits[chunk_index];
|
|
}
|
|
|
|
public void SetChunk(int chunk_index, ulong chunk_bits)
|
|
{
|
|
m_Bits[chunk_index] = (long)chunk_bits;
|
|
}
|
|
|
|
public unsafe ulong InterlockedReadChunk(int chunk_index)
|
|
{
|
|
long* entries = (long*)m_Bits.GetUnsafeReadOnlyPtr();
|
|
return (ulong)Interlocked.Read(ref entries[chunk_index]);
|
|
}
|
|
|
|
public unsafe void InterlockedOrChunk(int chunk_index, ulong chunk_bits)
|
|
{
|
|
long* entries = (long*)m_Bits.GetUnsafePtr();
|
|
|
|
long old_entry, new_entry;
|
|
do
|
|
{
|
|
old_entry = Interlocked.Read(ref entries[chunk_index]);
|
|
new_entry = old_entry | (long)chunk_bits;
|
|
} while (Interlocked.CompareExchange(ref entries[chunk_index], new_entry, old_entry) != old_entry);
|
|
}
|
|
|
|
public int ChunkCount()
|
|
{
|
|
return m_Bits.Length;
|
|
}
|
|
|
|
public ParallelBitArray GetSubArray(int length)
|
|
{
|
|
ParallelBitArray array = new ParallelBitArray();
|
|
array.m_Bits = m_Bits.GetSubArray(0, (length + 63) / 64);
|
|
array.m_Length = length;
|
|
return array;
|
|
}
|
|
|
|
public NativeArray<long> GetBitsArray()
|
|
{
|
|
return m_Bits;
|
|
}
|
|
|
|
public void FillZeroes(int length)
|
|
{
|
|
length = Math.Min(length, m_Length);
|
|
int chunkIndex = length / 64;
|
|
int remainder = length & 63;
|
|
|
|
m_Bits.FillArray(0, 0, chunkIndex);
|
|
|
|
if(remainder > 0)
|
|
{
|
|
long lastChunkMask = (1L << remainder) - 1;
|
|
m_Bits[chunkIndex] &= ~lastChunkMask;
|
|
}
|
|
}
|
|
}
|
|
}
|