feat(shader): refactor and enhance shader pipeline

Refactored the shader compilation pipeline to introduce modularity, improve performance, and enhance maintainability. Key changes include:

- Added `ShaderCompilationConfig`, `CompilerOptimizeLevel`, and `ShaderStage` enums.
- Replaced `SM` property with `ShaderModel` in shader models.
- Introduced `ShaderLibrary` for in-memory and disk-based shader caching.
- Refactored `DSLShaderCompiler` and `AntlrShaderCompiler` for better hashing and error handling.
- Centralized shader compilation logic in `ShaderCompilerUtility`.
- Removed legacy shader compilation logic from `IShaderCompiler`.
- Updated `RenderGraph`, `ResourceManager`, and `Material` to integrate with the new caching system.
- Improved memory management with `NativeMemoryManager<T>`.

BREAKING CHANGE: Removed legacy shader compilation methods and replaced them with a new caching and compilation system.
This commit is contained in:
2026-04-11 23:10:39 +09:00
parent f9a6e9cbbe
commit c66fda5332
30 changed files with 630 additions and 500 deletions

View File

@@ -1,8 +1,12 @@
using Ghost.Core.Utilities;
using System.IO.Hashing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ghost.Core.Graphics;
public enum ShaderModel
{
Invalid,
SM_6_6,
SM_6_7,
SM_6_8
@@ -20,6 +24,18 @@ public struct ShaderCode
public string entryPoint;
public readonly bool IsCreated => !string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(entryPoint);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ulong GetHashCode64()
{
return Hash.Combine64(XxHash64.HashToUInt64(MemoryMarshal.AsBytes(code.AsSpan())), XxHash64.HashToUInt64(MemoryMarshal.AsBytes(entryPoint.AsSpan())));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly int GetHashCode()
{
return HashCode.Combine(code, entryPoint);
}
}
public struct KeywordsGroup
@@ -53,7 +69,6 @@ public class GraphicsShaderDescriptor
public class ComputeShaderDescriptor
{
public required ulong identifier;
public required string name = string.Empty;
public required uint propertyBufferSize;
public required ShaderModel shaderModel;

View File

@@ -1,5 +1,6 @@
using Misaki.HighPerformance.LowLevel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ghost.Core;
@@ -260,6 +261,64 @@ public readonly ref struct RefResult<T, E>
public static implicit operator bool(RefResult<T, E> result) => result.IsSuccess;
}
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ResultTask
{
private readonly ValueTask<Result> _task;
public ResultTask(ValueTask<Result> task)
{
_task = task;
}
public ValueTaskAwaiter<Result> GetAwaiter() => _task.GetAwaiter();
public ValueTask<Result> AsValueTask() => _task;
public Task<Result> AsTask() => _task.AsTask();
public static implicit operator ResultTask(ValueTask<Result> task) => new ResultTask(task);
public static implicit operator ValueTask<Result>(ResultTask resultTask) => resultTask._task;
}
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ResultTask<T>
{
private readonly ValueTask<Result<T>> _task;
public ResultTask(ValueTask<Result<T>> task)
{
_task = task;
}
public ValueTaskAwaiter<Result<T>> GetAwaiter() => _task.GetAwaiter();
public ValueTask<Result<T>> AsValueTask() => _task;
public Task<Result<T>> AsTask() => _task.AsTask();
public static implicit operator ResultTask<T>(ValueTask<Result<T>> task) => new ResultTask<T>(task);
public static implicit operator ValueTask<Result<T>>(ResultTask<T> resultTask) => resultTask._task;
}
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ResultTask<T, E>
where E : struct, Enum
{
private readonly ValueTask<Result<T, E>> _task;
public ResultTask(ValueTask<Result<T, E>> task)
{
_task = task;
}
public ValueTaskAwaiter<Result<T, E>> GetAwaiter() => _task.GetAwaiter();
public ValueTask<Result<T, E>> AsValueTask() => _task;
public Task<Result<T, E>> AsTask() => _task.AsTask();
public static implicit operator ResultTask<T, E>(ValueTask<Result<T, E>> task) => new ResultTask<T, E>(task);
public static implicit operator ValueTask<Result<T, E>>(ResultTask<T, E> resultTask) => resultTask._task;
}
public static class ResultExtensions
{
extension(Error error)

View File

@@ -0,0 +1,46 @@
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
using System.Buffers;
namespace Ghost.Core.Utilities;
public unsafe class NativeMemoryManager<T> : MemoryManager<T>
where T : unmanaged
{
private readonly T* _pointer;
private readonly int _length;
public NativeMemoryManager(T* pointer, int length)
{
_pointer = pointer;
_length = length;
}
public static NativeMemoryManager<T> FromUnsafeCollection<C>(ref readonly C collection)
where C : unmanaged, IUnsafeCollection<T>
{
if (!collection.IsCreated)
{
throw new InvalidOperationException("The collection is not created.");
}
return new NativeMemoryManager<T>((T*)collection.GetUnsafePtr(), collection.Count);
}
public override Span<T> GetSpan()
{
return new Span<T>(_pointer, _length);
}
public override MemoryHandle Pin(int elementIndex = 0)
{
return new MemoryHandle(_pointer + elementIndex);
}
public override void Unpin()
{
}
protected override void Dispose(bool disposing)
{
}
}