Files
GhostEngine/Ghost.Shader.Concept/ShaderKeyword.cs
Misaki f988c34b3d Add high-performance material/shader system (Ghost.Shader.Concept)
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.
2025-12-26 19:19:30 +09:00

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;
}
}
}