Refactor: variant-aware shader/material pipeline overhaul

Major architectural update to graphics/material/shader system:
- Introduced strongly-typed key structs (Key64/Key128) for passes, variants, and pipelines; removed legacy key types.
- Implemented robust hashing and key generation utilities for efficient variant and pipeline lookup/caching.
- Shader compiler now compiles/caches all keyword variants using new key system; includes handled as lists.
- Switched to push constant root signature for per-draw data; updated HLSL and C# codegen accordingly.
- Refactored Material, Shader, and Pass data structures for cache efficiency and variant support.
- Pipeline library and PSO management now use 128-bit keys and variant-specific caching.
- Replaced WorldNode with SceneNode in editor/scene graph; introduced ComponentManager for archetype/query management.
- Migrated math utilities to Misaki.HighPerformance.Mathematics; updated editor controls.
- Updated all HLSL and codegen for new buffer/push constant layouts and macros.
- Misc: project reference cleanup, D3D12 Work Graph support, doc updates, and code modernization.
This commit is contained in:
2026-01-09 22:25:37 +09:00
parent c9be05fc60
commit 6a041f75ba
93 changed files with 1926 additions and 1390 deletions

View File

@@ -1,47 +1,20 @@
using System.Runtime.Intrinsics;
using TerraFX.Interop.Windows;
using ElementType = uint;
namespace Ghost.Graphics.Core;
public unsafe struct LocalKeywordSet
{
public struct ReadOnly
{
private LocalKeywordSet _set;
internal ReadOnly(LocalKeywordSet set)
{
_set = set;
}
public bool IsKeywordEnabled(int id)
{
return _set.IsKeywordEnabled(id);
}
public static ReadOnly operator |(in ReadOnly a, in ReadOnly b)
{
var resultSet = a._set | b._set;
return new ReadOnly(resultSet);
}
public static ReadOnly operator &(in ReadOnly a, in ReadOnly b)
{
var resultSet = a._set & b._set;
return new ReadOnly(resultSet);
}
}
private const int _DATA_ARRAY_LENGTH = 4; // 4 * 32 = 128 bits
private const int _SIZE_OF_ELEMENT = sizeof(ElementType);
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 / _SIZE_OF_ELEMENT;
var bit = localIndex % _SIZE_OF_ELEMENT;
var index = localIndex / _BITS_PER_ELEMENT;
var bit = localIndex % _BITS_PER_ELEMENT;
if (enabled)
{
_data[index] |= (uint)(1 << bit);
@@ -54,8 +27,8 @@ public unsafe struct LocalKeywordSet
public bool IsKeywordEnabled(int localIndex)
{
var index = localIndex / _SIZE_OF_ELEMENT;
var bit = localIndex % _SIZE_OF_ELEMENT;
var index = localIndex / _BITS_PER_ELEMENT;
var bit = localIndex % _BITS_PER_ELEMENT;
return (_data[index] & (uint)(1 << bit)) != 0;
}
@@ -67,11 +40,31 @@ public unsafe struct LocalKeywordSet
}
}
public readonly ReadOnly AsReadOnly()
public ulong GetHash64()
{
return new ReadOnly(this);
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);
@@ -83,10 +76,11 @@ public unsafe struct LocalKeywordSet
{
for (var i = 0; i < _DATA_ARRAY_LENGTH; i += Vector128<ElementType>.Count)
{
var vecA = Vector128.LoadUnsafe(ref *pDataA, (uint)(i * _SIZE_OF_ELEMENT));
var vecB = Vector128.LoadUnsafe(ref *pDataB, (uint)(i * _SIZE_OF_ELEMENT));
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], (uint)(i * _SIZE_OF_ELEMENT));
vecResult.StoreUnsafe(ref result._data[0], elementOffset);
}
}
}
@@ -112,10 +106,11 @@ public unsafe struct LocalKeywordSet
{
for (var i = 0; i < _DATA_ARRAY_LENGTH; i += Vector128<ElementType>.Count)
{
var vecA = Vector128.LoadUnsafe(ref *pDataA, (uint)(i * _SIZE_OF_ELEMENT));
var vecB = Vector128.LoadUnsafe(ref *pDataB, (uint)(i * _SIZE_OF_ELEMENT));
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], (uint)(i * _SIZE_OF_ELEMENT));
vecResult.StoreUnsafe(ref result._data[0], elementOffset);
}
}
}