106 lines
3.2 KiB
C#
106 lines
3.2 KiB
C#
|
using System;
|
||
|
|
||
|
namespace UnityEngine.Rendering.Universal
|
||
|
{
|
||
|
// A dynamic array of bits backed by a managed array of floats,
|
||
|
// since that's what Unity Shader constant API offers.
|
||
|
//
|
||
|
// Example:
|
||
|
// ShaderBitArray bits;
|
||
|
// bits.Resize(8);
|
||
|
// bits[0] = true;
|
||
|
// cmd.SetGlobalFloatArray("_BitArray", bits.data);
|
||
|
// bits.Clear();
|
||
|
internal struct ShaderBitArray
|
||
|
{
|
||
|
const int k_BitsPerElement = 32;
|
||
|
const int k_ElementShift = 5;
|
||
|
const int k_ElementMask = (1 << k_ElementShift) - 1;
|
||
|
|
||
|
private float[] m_Data;
|
||
|
|
||
|
public int elemLength => m_Data == null ? 0 : m_Data.Length;
|
||
|
public int bitCapacity => elemLength * k_BitsPerElement;
|
||
|
public float[] data => m_Data;
|
||
|
|
||
|
public void Resize(int bitCount)
|
||
|
{
|
||
|
if (bitCapacity > bitCount)
|
||
|
return;
|
||
|
|
||
|
int newElemCount = ((bitCount + (k_BitsPerElement - 1)) / k_BitsPerElement);
|
||
|
if (newElemCount == m_Data?.Length)
|
||
|
return;
|
||
|
|
||
|
var newData = new float[newElemCount];
|
||
|
if (m_Data != null)
|
||
|
{
|
||
|
for (int i = 0; i < m_Data.Length; i++)
|
||
|
newData[i] = m_Data[i];
|
||
|
}
|
||
|
m_Data = newData;
|
||
|
}
|
||
|
|
||
|
public void Clear()
|
||
|
{
|
||
|
for (int i = 0; i < m_Data.Length; i++)
|
||
|
m_Data[i] = 0;
|
||
|
}
|
||
|
|
||
|
private void GetElementIndexAndBitOffset(int index, out int elemIndex, out int bitOffset)
|
||
|
{
|
||
|
elemIndex = index >> k_ElementShift;
|
||
|
bitOffset = index & k_ElementMask;
|
||
|
}
|
||
|
|
||
|
public bool this[int index]
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
GetElementIndexAndBitOffset(index, out var elemIndex, out var bitOffset);
|
||
|
|
||
|
unsafe
|
||
|
{
|
||
|
fixed (float* floatData = m_Data)
|
||
|
{
|
||
|
uint* uintElem = (uint*)&floatData[elemIndex];
|
||
|
bool val = ((*uintElem) & (1u << bitOffset)) != 0u;
|
||
|
return val;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
GetElementIndexAndBitOffset(index, out var elemIndex, out var bitOffset);
|
||
|
unsafe
|
||
|
{
|
||
|
fixed (float* floatData = m_Data)
|
||
|
{
|
||
|
uint* uintElem = (uint*)&floatData[elemIndex];
|
||
|
if (value == true)
|
||
|
*uintElem = (*uintElem) | (1u << bitOffset);
|
||
|
else
|
||
|
*uintElem = (*uintElem) & ~(1u << bitOffset);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
unsafe
|
||
|
{
|
||
|
Debug.Assert(bitCapacity < 4096, "Bit string too long! It was truncated!");
|
||
|
int len = Math.Min(bitCapacity, 4096);
|
||
|
byte* buf = stackalloc byte[len];
|
||
|
for (int i = 0; i < len; i++)
|
||
|
{
|
||
|
buf[i] = (byte)(this[i] ? '1' : '0');
|
||
|
}
|
||
|
|
||
|
return new string((sbyte*)buf, 0, len, System.Text.Encoding.UTF8);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|