Introduces a new Ghost.Shader.Concept project implementing a modern, data-oriented material and shader system with: - Global/local keyword bitsets (fast O(1) ops, 64 bytes) - Multi-pass shader program and per-pass render state overrides - Thread-safe, 16-byte aligned material property blocks - Material pooling to reduce GC pressure - Batch renderer for efficient PSO grouping and async variant warmup - Full demo (Program.cs) and extensive documentation (ARCHITECTURE.md, README.md, PROJECT_SUMMARY.md) - Minor integration: new enums, doc updates, and keyword handling in existing code No breaking changes to the existing engine; all new code is isolated. This serves as a reference implementation for high-performance, extensible material/shader architectures.
78 lines
2.3 KiB
C#
78 lines
2.3 KiB
C#
namespace Ghost.Shader.Concept;
|
|
|
|
/// <summary>
|
|
/// Represents a shader keyword that can toggle shader features.
|
|
/// Keywords are immutable and interned for fast comparison.
|
|
/// </summary>
|
|
public readonly struct ShaderKeyword : IEquatable<ShaderKeyword>
|
|
{
|
|
private readonly int _id;
|
|
private readonly KeywordScope _scope;
|
|
|
|
public int Id => _id;
|
|
public KeywordScope Scope => _scope;
|
|
public bool IsValid => _id >= 0;
|
|
|
|
internal ShaderKeyword(int id, KeywordScope scope)
|
|
{
|
|
_id = id;
|
|
_scope = scope;
|
|
}
|
|
|
|
public bool Equals(ShaderKeyword other) => _id == other._id && _scope == other._scope;
|
|
public override bool Equals(object? obj) => obj is ShaderKeyword other && Equals(other);
|
|
public override int GetHashCode() => HashCode.Combine(_id, _scope);
|
|
|
|
public static bool operator ==(ShaderKeyword left, ShaderKeyword right) => left.Equals(right);
|
|
public static bool operator !=(ShaderKeyword left, ShaderKeyword right) => !left.Equals(right);
|
|
}
|
|
|
|
public enum KeywordScope : byte
|
|
{
|
|
/// <summary>Keywords set globally (e.g., platform, quality settings)</summary>
|
|
Global,
|
|
|
|
/// <summary>Keywords set per-material instance</summary>
|
|
Local
|
|
}
|
|
|
|
/// <summary>
|
|
/// Manages keyword registration and fast lookup.
|
|
/// Thread-safe for registration, lock-free for lookups.
|
|
/// </summary>
|
|
public sealed class ShaderKeywordRegistry
|
|
{
|
|
private readonly Dictionary<string, ShaderKeyword> _keywords = new();
|
|
private readonly Dictionary<int, string> _idToName = new();
|
|
private int _nextId = 0;
|
|
private readonly object _lock = new();
|
|
|
|
public static ShaderKeywordRegistry Instance { get; } = new();
|
|
|
|
private ShaderKeywordRegistry() { }
|
|
|
|
public ShaderKeyword GetOrRegister(string name, KeywordScope scope)
|
|
{
|
|
string key = $"{scope}:{name}";
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_keywords.TryGetValue(key, out var existing))
|
|
return existing;
|
|
|
|
var keyword = new ShaderKeyword(_nextId++, scope);
|
|
_keywords[key] = keyword;
|
|
_idToName[keyword.Id] = name;
|
|
return keyword;
|
|
}
|
|
}
|
|
|
|
public string? GetName(ShaderKeyword keyword)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _idToName.TryGetValue(keyword.Id, out var name) ? name : null;
|
|
}
|
|
}
|
|
}
|