Major architecture upgrade: - Add native render pass merging (hardware pass grouping, load/store op inference) - Implement heap-based aliasing for textures & buffers (D3D12-style) - Unify resource model: buffers and textures in one registry - Extend builder API for buffer creation/usage, access flags, hints - Improve barrier/state tracking (buffer hints, indirect argument state) - Update caching, hashing, and debug output for new model - Add enums/structs: AttachmentLoadOp, StoreOp, BufferHint, etc. - D3D12 backend: support named resources, temp upload buffers, correct heap usage - Update docs, benchmarks, and project files for new features Brings render graph closer to AAA engine standards, enabling efficient memory usage, lower driver overhead, and a more flexible API.
128 lines
3.5 KiB
C#
128 lines
3.5 KiB
C#
using System.Runtime.Intrinsics;
|
|
using TerraFX.Interop.Windows;
|
|
using ElementType = uint;
|
|
|
|
namespace Ghost.Graphics.Core;
|
|
|
|
public unsafe struct LocalKeywordSet
|
|
{
|
|
private const int _DATA_ARRAY_LENGTH = 4; // 4 * 32 = 128 bits
|
|
private const int _BITS_PER_ELEMENT = sizeof(ElementType) * 8;
|
|
|
|
private fixed ElementType _data[_DATA_ARRAY_LENGTH];
|
|
|
|
public void SetKeyword(int localIndex, bool enabled)
|
|
{
|
|
var index = localIndex / _BITS_PER_ELEMENT;
|
|
var bit = localIndex % _BITS_PER_ELEMENT;
|
|
if (enabled)
|
|
{
|
|
_data[index] |= (uint)(1 << bit);
|
|
}
|
|
else
|
|
{
|
|
_data[index] &= ~(uint)(1 << bit);
|
|
}
|
|
}
|
|
|
|
public bool IsKeywordEnabled(int localIndex)
|
|
{
|
|
var index = localIndex / _BITS_PER_ELEMENT;
|
|
var bit = localIndex % _BITS_PER_ELEMENT;
|
|
return (_data[index] & (uint)(1 << bit)) != 0;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
|
{
|
|
_data[i] = 0;
|
|
}
|
|
}
|
|
|
|
public ulong GetHash64()
|
|
{
|
|
ulong hash = 14695981039346656037ul; // FNV Offset basis
|
|
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
|
{
|
|
hash ^= _data[i];
|
|
hash *= 1099511628211ul; // FNV prime
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = 17;
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
|
{
|
|
hash = hash * 31 + _data[i].GetHashCode();
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
|
|
public static LocalKeywordSet operator |(in LocalKeywordSet a, in LocalKeywordSet b)
|
|
{
|
|
var result = default(LocalKeywordSet);
|
|
|
|
if (Vector128<ElementType>.IsSupported)
|
|
{
|
|
fixed (ElementType* pDataA = a._data)
|
|
fixed (ElementType* pDataB = b._data)
|
|
{
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i += Vector128<ElementType>.Count)
|
|
{
|
|
var elementOffset = (nuint)i;
|
|
var vecA = Vector128.LoadUnsafe(ref *pDataA, elementOffset);
|
|
var vecB = Vector128.LoadUnsafe(ref *pDataB, elementOffset);
|
|
var vecResult = Vector128.BitwiseOr(vecA, vecB);
|
|
vecResult.StoreUnsafe(ref result._data[0], elementOffset);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
|
{
|
|
result._data[i] = a._data[i] | b._data[i];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static LocalKeywordSet operator &(in LocalKeywordSet a, in LocalKeywordSet b)
|
|
{
|
|
var result = default(LocalKeywordSet);
|
|
|
|
if (Vector128<ElementType>.IsSupported)
|
|
{
|
|
fixed (ElementType* pDataA = a._data)
|
|
fixed (ElementType* pDataB = b._data)
|
|
{
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i += Vector128<ElementType>.Count)
|
|
{
|
|
var elementOffset = (nuint)i;
|
|
var vecA = Vector128.LoadUnsafe(ref *pDataA, elementOffset);
|
|
var vecB = Vector128.LoadUnsafe(ref *pDataB, elementOffset);
|
|
var vecResult = Vector128.BitwiseAnd(vecA, vecB);
|
|
vecResult.StoreUnsafe(ref result._data[0], elementOffset);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
|
{
|
|
result._data[i] = a._data[i] & b._data[i];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |