Added IShaderCompiler

This commit is contained in:
2025-11-16 19:50:24 +09:00
parent d91d6f6e57
commit 5c4e1a3350
15 changed files with 595 additions and 372 deletions

View File

@@ -22,6 +22,11 @@ public readonly struct Result
return new Result(false, message); return new Result(false, message);
} }
public static Result<T> Success<T>(T value)
{
return Result<T>.Success(value);
}
public override string ToString() => success ? "OK" : $"Error: {message}"; public override string ToString() => success ? "OK" : $"Error: {message}";
public static implicit operator bool(Result result) => result.success; public static implicit operator bool(Result result) => result.success;
@@ -34,16 +39,16 @@ public readonly struct Result<T>
public readonly string? message; public readonly string? message;
public Result(bool success, T data, string? message = null) public Result(bool success, T value, string? message = null)
{ {
this.success = success; this.success = success;
this.value = data; this.value = value;
this.message = message; this.message = message;
} }
public static Result<T> Success(T data) public static Result<T> Success(T value)
{ {
return new Result<T>(true, data); return new Result<T>(true, value);
} }
public static Result<T> Fail(string? message) public static Result<T> Fail(string? message)

View File

@@ -1,3 +1,4 @@
using Misaki.HighPerformance.LowLevel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -97,4 +98,18 @@ internal static unsafe partial class Win32Utility
{ {
return (flags & Unsafe.As<T, uint>(ref flag)) != 0; return (flags & Unsafe.As<T, uint>(ref flag)) != 0;
} }
extension(MemoryLeakException)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Conditional("DEBUG")]
[Conditional("GHOST_EDITOR")]
public static void ThrowIfRefCountNonZero(uint count)
{
if (count != 0)
{
throw new MemoryLeakException($"Reference count is not zero: {count}");
}
}
}
} }

View File

@@ -1,5 +1,4 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Core.Graphics;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Collections;
@@ -123,7 +122,7 @@ public unsafe readonly ref struct RenderingContext
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<byte> data) public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<byte> data)
{ {
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()); var desc = ResourceDatabase.GetResourceDescription(texture.AsResource());
desc.textureDescription.Format.GetSurfaceInfo((int)desc.textureDescription.Width, (int)desc.textureDescription.Height, out var rowPitch, out var slicePitch, out _); desc.TextureDescription.Format.GetSurfaceInfo((int)desc.TextureDescription.Width, (int)desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
var subresourceData = new SubResourceData var subresourceData = new SubResourceData
{ {
@@ -159,12 +158,12 @@ public unsafe readonly ref struct RenderingContext
shader.TryGetPassKey(passName, out var passIndex, out var passKey); shader.TryGetPassKey(passName, out var passIndex, out var passKey);
var hash = new GraphicsPipelineHash var hash = new GraphicsPipelineHash
{ {
id = passKey, Id = passKey,
rtvCount = 1, RtvCount = 1,
dsvFormat = TextureFormat.Unknown, DsvFormat = TextureFormat.Unknown,
}; };
hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm; hash.RtvFormats[0] = TextureFormat.B8G8R8A8_UNorm;
var pipelineKey = hash.GetKey(); var pipelineKey = hash.GetKey();
_directCmd.SetPipelineState(pipelineKey); _directCmd.SetPipelineState(pipelineKey);

View File

@@ -1,4 +1,4 @@
namespace Ghost.Core.Graphics; namespace Ghost.Graphics.Core;
/// <summary> /// <summary>
/// The layout of the root signature is: /// The layout of the root signature is:
@@ -32,4 +32,12 @@ public static class RootSignatureLayout
public const int TEXTURE_HEAP_SLOT = 0; public const int TEXTURE_HEAP_SLOT = 0;
public const int SAMPLER_HEAP_SLOT = 0; public const int SAMPLER_HEAP_SLOT = 0;
public const int ROOT_PARAMETER_COUNT =
#if USE_TRADITIONAL_BINDLESS
6
#else
4
#endif
;
} }

View File

@@ -1,8 +1,9 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Core.Graphics; using Ghost.Core.Utilities;
using Ghost.Graphics.Core; using Ghost.Graphics.Core;
using Ghost.Graphics.D3D12.Utilities; using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Utilities; using Misaki.HighPerformance.LowLevel.Utilities;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX; using TerraFX.Interop.DirectX;
@@ -13,10 +14,9 @@ using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12; namespace Ghost.Graphics.D3D12;
internal unsafe class D3D12CommandBuffer : ICommandBuffer internal unsafe class D3D12CommandBuffer : D3D12RHIObject<ID3D12GraphicsCommandList10>, ICommandBuffer
{ {
private ComPtr<ID3D12CommandAllocator> _allocator; private ComPtr<ID3D12CommandAllocator> _allocator;
private ComPtr<ID3D12GraphicsCommandList10> _commandList;
private readonly D3D12PipelineLibrary _pipelineLibrary; private readonly D3D12PipelineLibrary _pipelineLibrary;
private readonly D3D12ResourceDatabase _resourceDatabase; private readonly D3D12ResourceDatabase _resourceDatabase;
@@ -24,26 +24,14 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
private readonly D3D12DescriptorAllocator _descriptorAllocator; private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly CommandBufferType _type; private readonly CommandBufferType _type;
private string _name;
private ushort _commandCount; private ushort _commandCount;
private bool _isRecording; private bool _isRecording;
private bool _disposed;
public ID3D12GraphicsCommandList10* NativeCommandList => _commandList.Get(); public ID3D12GraphicsCommandList10* NativeCommandList => nativeObject.Get();
public CommandBufferType Type => _type; public CommandBufferType Type => _type;
public bool IsEmpty => _commandCount == 0; public bool IsEmpty => _commandCount == 0;
public string Name
{
get => _name;
set
{
_name = value;
_commandList.Get()->SetName(value);
}
}
public D3D12CommandBuffer( public D3D12CommandBuffer(
D3D12RenderDevice device, D3D12RenderDevice device,
D3D12PipelineLibrary stateController, D3D12PipelineLibrary stateController,
@@ -52,7 +40,6 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
D3D12DescriptorAllocator descriptorAllocator, D3D12DescriptorAllocator descriptorAllocator,
CommandBufferType type) CommandBufferType type)
{ {
_name = string.Empty;
_type = type; _type = type;
ID3D12CommandAllocator* pAllocator = default; ID3D12CommandAllocator* pAllocator = default;
@@ -63,7 +50,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList); device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
_allocator.Attach(pAllocator); _allocator.Attach(pAllocator);
_commandList.Attach(pCommandList); nativeObject.Attach(pCommandList);
_pipelineLibrary = stateController; _pipelineLibrary = stateController;
_resourceDatabase = resourceDatabase; _resourceDatabase = resourceDatabase;
@@ -71,12 +58,6 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_descriptorAllocator = descriptorAllocator; _descriptorAllocator = descriptorAllocator;
_isRecording = false; _isRecording = false;
_disposed = false;
}
~D3D12CommandBuffer()
{
Dispose();
} }
private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type) private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type)
@@ -90,12 +71,6 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
}; };
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfRecording() private void ThrowIfRecording()
{ {
@@ -125,7 +100,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
void ResetCommandList() void ResetCommandList()
{ {
ThrowIfFailed(_allocator.Get()->Reset()); ThrowIfFailed(_allocator.Get()->Reset());
ThrowIfFailed(_commandList.Get()->Reset(_allocator.Get(), null)); ThrowIfFailed(nativeObject.Get()->Reset(_allocator.Get(), null));
} }
void SetBindlessHeap() void SetBindlessHeap()
@@ -133,7 +108,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var heaps = stackalloc ID3D12DescriptorHeap*[2]; var heaps = stackalloc ID3D12DescriptorHeap*[2];
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
_commandList.Get()->SetDescriptorHeaps(2, heaps); nativeObject.Get()->SetDescriptorHeaps(2, heaps);
} }
ThrowIfDisposed(); ThrowIfDisposed();
@@ -151,7 +126,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotRecording(); ThrowIfNotRecording();
_commandList.Get()->Close(); nativeObject.Get()->Close();
_isRecording = false; _isRecording = false;
} }
@@ -161,8 +136,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
var d3d12Rect = new RECT((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom); var d3d12Rect = new RECT((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect); nativeObject.Get()->RSSetScissorRects(1, &d3d12Rect);
} }
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after) public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
@@ -175,7 +150,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource, var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
before.ToD3D12States(), after.ToD3D12States()); before.ToD3D12States(), after.ToD3D12States());
_commandList.Get()->ResourceBarrier(1, &barrier); nativeObject.Get()->ResourceBarrier(1, &barrier);
} }
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget) public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
@@ -203,7 +178,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv); pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv);
} }
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle); nativeObject.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
} }
public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false) public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false)
@@ -216,12 +191,12 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
for (var i = 0; i < rtDescs.Length; i++) for (var i = 0; i < rtDescs.Length; i++)
{ {
var rtDesc = rtDescs[i]; var rtDesc = rtDescs[i];
if (!rtDesc.texture.IsValid) if (!rtDesc.Texture.IsValid)
{ {
throw new ArgumentException($"Render target at index {i} is not a valid texture handle"); throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
} }
var resourceInfo = _resourceDatabase.GetResourceInfo(rtDesc.texture.AsResource()); var resourceInfo = _resourceDatabase.GetResourceInfo(rtDesc.Texture.AsResource());
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv); var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv);
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
@@ -234,24 +209,24 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
{ {
ClearValue = new D3D12_CLEAR_VALUE ClearValue = new D3D12_CLEAR_VALUE
{ {
Format = resourceInfo.desc.textureDescription.Format.ToDXGIFormat(), Format = resourceInfo.desc.TextureDescription.Format.ToDXGIFormat(),
} }
} }
} }
}; };
desc.BeginningAccess.Clear.ClearValue.Color[0] = rtDesc.clearColor.r; desc.BeginningAccess.Clear.ClearValue.Color[0] = rtDesc.ClearColor.r;
desc.BeginningAccess.Clear.ClearValue.Color[1] = rtDesc.clearColor.g; desc.BeginningAccess.Clear.ClearValue.Color[1] = rtDesc.ClearColor.g;
desc.BeginningAccess.Clear.ClearValue.Color[2] = rtDesc.clearColor.b; desc.BeginningAccess.Clear.ClearValue.Color[2] = rtDesc.ClearColor.b;
desc.BeginningAccess.Clear.ClearValue.Color[3] = rtDesc.clearColor.a; desc.BeginningAccess.Clear.ClearValue.Color[3] = rtDesc.ClearColor.a;
pRtvDescs[i] = desc; pRtvDescs[i] = desc;
} }
var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.texture.IsValid ? 1 : 0]; var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.Texture.IsValid ? 1 : 0];
if (pDsvDesc != null) if (pDsvDesc != null)
{ {
var resourceInfo = _resourceDatabase.GetResourceInfo(depthDesc.texture.AsResource()); var resourceInfo = _resourceDatabase.GetResourceInfo(depthDesc.Texture.AsResource());
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv); var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv);
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
@@ -264,11 +239,11 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
{ {
ClearValue = new D3D12_CLEAR_VALUE ClearValue = new D3D12_CLEAR_VALUE
{ {
Format = resourceInfo.desc.textureDescription.Format.ToDXGIFormat(), Format = resourceInfo.desc.TextureDescription.Format.ToDXGIFormat(),
DepthStencil = new D3D12_DEPTH_STENCIL_VALUE DepthStencil = new D3D12_DEPTH_STENCIL_VALUE
{ {
Depth = depthDesc.clearDepth, Depth = depthDesc.ClearDepth,
Stencil = depthDesc.clearStencil Stencil = depthDesc.ClearStencil
} }
} }
} }
@@ -278,7 +253,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
pDsvDesc[0] = desc; pDsvDesc[0] = desc;
} }
_commandList.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc, nativeObject.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE); allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE);
} }
@@ -288,7 +263,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
_commandList.Get()->EndRenderPass(); nativeObject.Get()->EndRenderPass();
} }
public void SetViewport(ViewportDesc viewport) public void SetViewport(ViewportDesc viewport)
@@ -297,8 +272,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
var d3d12Viewport = new D3D12_VIEWPORT(viewport.width, viewport.height, viewport.x, viewport.y, viewport.minDepth, viewport.maxDepth); var d3d12Viewport = new D3D12_VIEWPORT(viewport.Width, viewport.Height, viewport.X, viewport.Y, viewport.MinDepth, viewport.MaxDepth);
_commandList.Get()->RSSetViewports(1, &d3d12Viewport); nativeObject.Get()->RSSetViewports(1, &d3d12Viewport);
} }
public void SetPipelineState(GraphicsPipelineKey pipelineKey) public void SetPipelineState(GraphicsPipelineKey pipelineKey)
@@ -308,7 +283,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
IncrementCommandCount(); IncrementCommandCount();
var shaderPipeline = _pipelineLibrary.GetGraphicsPSO(pipelineKey).GetValueOrThrow(); var shaderPipeline = _pipelineLibrary.GetGraphicsPSO(pipelineKey).GetValueOrThrow();
_commandList.Get()->SetPipelineState(shaderPipeline.value); nativeObject.Get()->SetPipelineState(shaderPipeline.value);
} }
public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer) public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer)
@@ -318,7 +293,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
IncrementCommandCount(); IncrementCommandCount();
var resource = _resourceDatabase.GetResource(buffer.AsResource()); var resource = _resourceDatabase.GetResource(buffer.AsResource());
_commandList.Get()->SetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress()); nativeObject.Get()->SetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress());
} }
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0) public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
@@ -332,10 +307,10 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
{ {
BufferLocation = pResource->GetGPUVirtualAddress() + offset, BufferLocation = pResource->GetGPUVirtualAddress() + offset,
SizeInBytes = (uint)(pResource->GetDesc().Width - offset), SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).bufferDescription.Stride StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).BufferDescription.Stride
}; };
_commandList.Get()->IASetVertexBuffers(slot, 1, &vbView); nativeObject.Get()->IASetVertexBuffers(slot, 1, &vbView);
} }
public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0) public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0)
@@ -352,7 +327,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT
}; };
_commandList.Get()->IASetIndexBuffer(&ibView); nativeObject.Get()->IASetIndexBuffer(&ibView);
} }
public void SetPrimitiveTopology(PrimitiveTopology topology) public void SetPrimitiveTopology(PrimitiveTopology topology)
@@ -369,7 +344,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST _ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
}; };
_commandList.Get()->IASetPrimitiveTopology(d3d12Topology); nativeObject.Get()->IASetPrimitiveTopology(d3d12Topology);
} }
public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0) public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0)
@@ -378,7 +353,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
_commandList.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance); nativeObject.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance);
} }
public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0) public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0)
@@ -387,7 +362,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
_commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance); nativeObject.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
} }
public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ) public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
@@ -396,7 +371,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
_commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ); nativeObject.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
} }
public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ) public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
@@ -405,7 +380,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording(); ThrowIfNotRecording();
IncrementCommandCount(); IncrementCommandCount();
_commandList.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ); nativeObject.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
} }
public void DispatchRay() public void DispatchRay()
@@ -416,7 +391,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
// ThrowIfNotRecording(); // ThrowIfNotRecording();
// IncrementCommandCount(); // IncrementCommandCount();
// _commandList.Get()->DispatchRays(); // nativeObject.Get()->DispatchRays();
} }
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data) public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
@@ -441,7 +416,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var pResource = _resourceDatabase.GetResource(buffer.AsResource()); var pResource = _resourceDatabase.GetResource(buffer.AsResource());
_commandList.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes); nativeObject.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes);
} }
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources) public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
@@ -470,7 +445,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
} }
UpdateSubresources( UpdateSubresources(
(ID3D12GraphicsCommandList*)_commandList.Get(), (ID3D12GraphicsCommandList*)nativeObject.Get(),
pResource, pResource,
pUploadResource, pUploadResource,
0, 0,
@@ -494,17 +469,17 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
if (numBytes == 0) if (numBytes == 0)
{ {
_commandList.Get()->CopyResource(pDestResource, pSrcResource); nativeObject.Get()->CopyResource(pDestResource, pSrcResource);
} }
else else
{ {
_commandList.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes); nativeObject.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes);
} }
} }
public void Dispose() protected override void Dispose(bool disposing)
{ {
if (_disposed) if (IsDisposed)
{ {
return; return;
} }
@@ -514,12 +489,9 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
throw new InvalidOperationException("Command buffer is still recording"); throw new InvalidOperationException("Command buffer is still recording");
} }
_commandList.Dispose(); MemoryLeakException.ThrowIfRefCountNonZero(_allocator.Reset());
_allocator.Dispose();
_isRecording = false;
_commandCount = 0; _commandCount = 0;
_disposed = true;
GC.SuppressFinalize(this); base.Dispose(disposing);
} }
} }

View File

@@ -1,6 +1,7 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Core.Graphics; using Ghost.Core.Graphics;
using Ghost.Core.Utilities; using Ghost.Core.Utilities;
using Ghost.Graphics.Core;
using Ghost.Graphics.D3D12.Utilities; using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Buffer;
@@ -45,14 +46,6 @@ internal struct D3D12PipelineState : IDisposable
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
{ {
private const int rootParamCount =
#if USE_TRADITIONAL_BINDLESS
6
#else
4
#endif
;
private readonly D3D12RenderDevice _device; private readonly D3D12RenderDevice _device;
private readonly D3D12ResourceDatabase _resourceDatabase; private readonly D3D12ResourceDatabase _resourceDatabase;
@@ -81,7 +74,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
_defaultRootSignature = default; _defaultRootSignature = default;
// NOTE: Since we are targeting SM 6.6, we can use ResourceDescriptorHeap and SamplerDescriptorHeap directly without needing to set up viewGroup tables. // NOTE: Since we are targeting SM 6.6, we can use ResourceDescriptorHeap and SamplerDescriptorHeap directly without needing to set up viewGroup tables.
var rootParameters = stackalloc D3D12_ROOT_PARAMETER1[rootParamCount]; var rootParameters = stackalloc D3D12_ROOT_PARAMETER1[RootSignatureLayout.ROOT_PARAMETER_COUNT];
rootParameters[0] = new D3D12_ROOT_PARAMETER1 rootParameters[0] = new D3D12_ROOT_PARAMETER1
{ {
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV, ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
@@ -144,7 +137,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC1 var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC1
{ {
NumParameters = rootParamCount, NumParameters = RootSignatureLayout.ROOT_PARAMETER_COUNT,
pParameters = rootParameters, pParameters = rootParameters,
NumStaticSamplers = 0, NumStaticSamplers = 0,
pStaticSamplers = null, pStaticSamplers = null,
@@ -215,19 +208,38 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
fs.Write(buffer.AsSpan()); fs.Write(buffer.AsSpan());
} }
private static CBufferInfo ValidateReflectionData(FullPassDescriptor descriptor, ShaderReflectionData reflectionData) private static Result<CBufferInfo> ValidateReflectionData(FullPassDescriptor descriptor, ShaderReflectionData reflectionData)
{ {
if (reflectionData.ConstantBuffers.Count != rootParamCount) CBufferInfo cbufferInfo = default;
foreach (var info in reflectionData.ResourcesBindings)
{ {
throw new InvalidOperationException($"Shader reflection data has {reflectionData.ConstantBuffers.Count} constant buffers, expected {rootParamCount}"); if (info.BindPoint > 3)
{
return Result.Fail($"Resource binding point {info.BindPoint} is out of range. Only binding points 0-3 are supported in the current root signature.");
} }
if (reflectionData.OtherResources.Count != 0) if (info.Type != D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER)
{ {
throw new NotSupportedException("Shader reflection data contains unsupported resource types. Only constant buffers are supported in the current root signature."); return Result.Fail($"Resource binding type {info.Type} is not supported. Only constant buffers are supported in the current root signature.");
} }
return reflectionData.ConstantBuffers[RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT]; if (info.BindPoint == RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT)
{
cbufferInfo = new CBufferInfo
{
Name = info.Name,
RegisterSlot = info.BindPoint,
RegisterSpace = info.Space,
SizeInBytes = info.Size,
Properties = info.Properties ?? Array.Empty<CBufferPropertyInfo>(),
};
return Result.Success(cbufferInfo);
}
}
return Result.Fail("Per-material constant buffer not found in shader reflection data.");
// TODO: Validate Cbuffer sizes and bindings. // TODO: Validate Cbuffer sizes and bindings.
} }
@@ -242,11 +254,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
try try
{ {
// TODO: This does not include generated code. This will cause a root signature mismatch. // TODO: This does not include generated code. This will cause a root signature mismatch.
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow(); var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, (void**)&reflectionBlob).GetValueOrThrow();
if (reflectionBlob != null) if (reflectionBlob != null)
{ {
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow(); var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
cbufferInfo = ValidateReflectionData(descriptor, reflection); cbufferInfo = ValidateReflectionData(descriptor, reflection).GetValueOrThrow();
} }
return result; return result;
@@ -361,7 +373,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
private GraphicsPipelineKey CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly D3D12GraphicsCompiledResult compiled) private GraphicsPipelineKey CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly D3D12GraphicsCompiledResult compiled)
{ {
var rtvCount = (uint)Math.Min(descriptor.rtvFormats.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT); var rtvCount = (uint)Math.Min(descriptor.RtvFormats.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
{ {
@@ -372,12 +384,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
SampleMask = UINT32_MAX, SampleMask = UINT32_MAX,
SampleDesc = new DXGI_SAMPLE_DESC(1, 0), SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
NumRenderTargets = rtvCount, NumRenderTargets = rtvCount,
DSVFormat = descriptor.dsvFormat.ToDXGIFormat(), DSVFormat = descriptor.DsvFormat.ToDXGIFormat(),
DepthStencilState = BuildDepthStencil(descriptor.zTest, descriptor.zWrite), DepthStencilState = BuildDepthStencil(descriptor.ZTest, descriptor.ZWrite),
NodeMask = 0, NodeMask = 0,
Flags = D3D12_PIPELINE_STATE_FLAG_NONE, Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
BlendState = descriptor.blend switch BlendState = descriptor.Blend switch
{ {
BlendOptions.Opaque => D3D12Utility.D3D12_BLEND_DESC_OPAQUE, BlendOptions.Opaque => D3D12Utility.D3D12_BLEND_DESC_OPAQUE,
BlendOptions.Alpha => D3D12Utility.D3D12_BLEND_DESC_ALPHA_BLEND, BlendOptions.Alpha => D3D12Utility.D3D12_BLEND_DESC_ALPHA_BLEND,
@@ -386,7 +398,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
BlendOptions.PremultipliedAlpha => D3D12Utility.D3D12_BLEND_DESC_PREMULTIPLIED, BlendOptions.PremultipliedAlpha => D3D12Utility.D3D12_BLEND_DESC_PREMULTIPLIED,
_ => D3D12Utility.D3D12_BLEND_DESC_OPAQUE _ => D3D12Utility.D3D12_BLEND_DESC_OPAQUE
}, },
RasterizerState = descriptor.cull switch RasterizerState = descriptor.Cull switch
{ {
CullOptions.Off => D3D12Utility.D3D12_RASTERIZER_DESC_CULL_NONE, CullOptions.Off => D3D12Utility.D3D12_RASTERIZER_DESC_CULL_NONE,
CullOptions.Front => D3D12Utility.D3D12_RASTERIZER_DESC_CULL_CLOCKWISE, CullOptions.Front => D3D12Utility.D3D12_RASTERIZER_DESC_CULL_CLOCKWISE,
@@ -402,16 +414,16 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
var hash = new GraphicsPipelineHash var hash = new GraphicsPipelineHash
{ {
id = descriptor.passId, Id = descriptor.PassId,
rtvCount = (uint)descriptor.rtvFormats.Length, RtvCount = (uint)descriptor.RtvFormats.Length,
dsvFormat = descriptor.dsvFormat, DsvFormat = descriptor.DsvFormat,
}; };
for (var i = 0; i < rtvCount && i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) for (var i = 0; i < rtvCount && i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{ {
desc.RTVFormats[i] = descriptor.rtvFormats[i].ToDXGIFormat(); desc.RTVFormats[i] = descriptor.RtvFormats[i].ToDXGIFormat();
desc.BlendState.RenderTarget[i].RenderTargetWriteMask = (byte)(descriptor.colorMask & 0x0F); desc.BlendState.RenderTarget[i].RenderTargetWriteMask = (byte)(descriptor.ColorMask & 0x0F);
hash.rtvFormats[i] = descriptor.rtvFormats[i]; hash.RtvFormats[i] = descriptor.RtvFormats[i];
} }
var key = hash.GetKey(); var key = hash.GetKey();
@@ -468,15 +480,15 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
var psoDes = new GraphicsPSODescriptor var psoDes = new GraphicsPSODescriptor
{ {
passId = new ShaderPassKey(fullPass.Identifier), PassId = new ShaderPassKey(fullPass.Identifier),
zTest = fullPass.localPipeline.zTest, ZTest = fullPass.localPipeline.zTest,
zWrite = fullPass.localPipeline.zWrite, ZWrite = fullPass.localPipeline.zWrite,
cull = fullPass.localPipeline.cull, Cull = fullPass.localPipeline.cull,
blend = fullPass.localPipeline.blend, Blend = fullPass.localPipeline.blend,
colorMask = fullPass.localPipeline.colorMask, ColorMask = fullPass.localPipeline.colorMask,
rtvFormats = rtvs, RtvFormats = rtvs,
dsvFormat = dsv, DsvFormat = dsv,
}; };
key = CompilePSO(in psoDes, in compiled); key = CompilePSO(in psoDes, in compiled);

View File

@@ -0,0 +1,67 @@
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Ghost.Graphics.D3D12;
internal abstract unsafe class D3D12RHIObject<T> : IRHIObject, IDisposable
where T : unmanaged, ID3D12Object.Interface
{
private bool _disposed;
private string _name = string.Empty;
protected ComPtr<T> nativeObject;
protected bool IsDisposed => _disposed;
public string Name
{
get => _name;
set
{
if (_name == value)
{
return;
}
_name = value;
if (nativeObject.Get() != null)
{
nativeObject.Get()->SetName(value);
}
}
}
~D3D12RHIObject()
{
Dispose(false);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void ThrowIfDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
MemoryLeakException.ThrowIfRefCountNonZero(nativeObject.Reset());
_disposed = true;
}
}

View File

@@ -199,15 +199,15 @@ internal unsafe class D3D12Renderer : IRenderer
Span<PassRenderTargetDesc> rtDesc = stackalloc PassRenderTargetDesc[1]; Span<PassRenderTargetDesc> rtDesc = stackalloc PassRenderTargetDesc[1];
rtDesc[0] = new PassRenderTargetDesc rtDesc[0] = new PassRenderTargetDesc
{ {
texture = target, Texture = target,
clearColor = clearColor, ClearColor = clearColor,
}; };
var depthDesc = new PassDepthStencilDesc var depthDesc = new PassDepthStencilDesc
{ {
texture = Handle<Texture>.Invalid, Texture = Handle<Texture>.Invalid,
clearDepth = 1.0f, ClearDepth = 1.0f,
clearStencil = 0, ClearStencil = 0,
}; };
// NOTE: Testing only. // NOTE: Testing only.
@@ -219,8 +219,8 @@ internal unsafe class D3D12Renderer : IRenderer
cmd.BeginRenderPass(rtDesc, depthDesc, false); cmd.BeginRenderPass(rtDesc, depthDesc, false);
var viewport = new ViewportDesc { width = _currentSize.x, height = _currentSize.y, minDepth = 0, maxDepth = 1 }; var viewport = new ViewportDesc { Width = _currentSize.x, Height = _currentSize.y, MinDepth = 0, MaxDepth = 1 };
var scissor = new RectDesc { right = _currentSize.x, bottom = _currentSize.y }; var scissor = new RectDesc { Right = _currentSize.x, Bottom = _currentSize.y };
cmd.SetViewport(viewport); cmd.SetViewport(viewport);
cmd.SetScissorRect(scissor); cmd.SetScissorRect(scissor);

View File

@@ -10,70 +10,7 @@ using static TerraFX.Interop.DirectX.DXC;
namespace Ghost.Graphics.D3D12; namespace Ghost.Graphics.D3D12;
internal struct CompileResult : IDisposable internal partial class D3D12ShaderCompiler
{
public UnsafeArray<byte> bytecode;
public readonly bool IsCreated => bytecode.IsCreated;
public void Dispose()
{
bytecode.Dispose();
}
}
internal readonly struct ResourceBindingInfo
{
public string Name
{
get; init;
}
public D3D_SHADER_INPUT_TYPE Type
{
get; init;
}
public uint BindPoint
{
get; init;
}
public uint BindCount
{
get; init;
}
public uint Space
{
get; init;
}
}
internal readonly struct ShaderReflectionData
{
public List<CBufferInfo> ConstantBuffers
{
get;
}
public List<ResourceBindingInfo> OtherResources
{
get;
}
// public List<ResourceBindingInfo> Samplers { get; } = new();
// public List<ResourceBindingInfo> ShaderResourceViews { get; } = new();
// public List<ResourceBindingInfo> UnorderedAccessViews { get; } = new();
public ShaderReflectionData()
{
ConstantBuffers = new List<CBufferInfo>();
OtherResources = new List<ResourceBindingInfo>();
}
}
internal static unsafe class D3D12ShaderCompiler
{ {
private static string GetProfileString(ShaderStage stage, CompilerTier version) private static string GetProfileString(ShaderStage stage, CompilerTier version)
{ {
@@ -150,29 +87,63 @@ internal static unsafe class D3D12ShaderCompiler
return argsArray; return argsArray;
} }
public static Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator, IDxcBlob** ppReflectionBlob) private static ShaderInputType ToInputType(D3D_SHADER_INPUT_TYPE type)
{ {
// NOTE: Should we cache the pCompiler and pUtils instances for better performance? return type switch
{
D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER => ShaderInputType.ConstantBuffer,
D3D_SHADER_INPUT_TYPE.D3D_SIT_TBUFFER => ShaderInputType.Texture,
D3D_SHADER_INPUT_TYPE.D3D_SIT_TEXTURE => ShaderInputType.Texture,
D3D_SHADER_INPUT_TYPE.D3D_SIT_SAMPLER => ShaderInputType.Sampler,
D3D_SHADER_INPUT_TYPE.D3D_SIT_UAV_RWTYPED => ShaderInputType.UAV,
D3D_SHADER_INPUT_TYPE.D3D_SIT_STRUCTURED => ShaderInputType.StructuredBuffer,
D3D_SHADER_INPUT_TYPE.D3D_SIT_BYTEADDRESS => ShaderInputType.ByteAddressBuffer,
D3D_SHADER_INPUT_TYPE.D3D_SIT_UAV_RWSTRUCTURED => ShaderInputType.RWStructuredBuffer,
D3D_SHADER_INPUT_TYPE.D3D_SIT_UAV_RWBYTEADDRESS => ShaderInputType.RWByteAddressBuffer,
_ => throw new ArgumentOutOfRangeException(nameof(type), "Unsupported shader input type")
};
}
}
internal unsafe partial class D3D12ShaderCompiler : IShaderCompiler
{
private ComPtr<IDxcCompiler3> _compiler;
private ComPtr<IDxcUtils> _utils;
public D3D12ShaderCompiler()
{
// Initialize DXC _compiler.Get() and _utils.Get()
var dxccID = CLSID.CLSID_DxcCompiler;
var dxcuID = CLSID.CLSID_DxcUtils;
IDxcCompiler3* pCompiler = default; IDxcCompiler3* pCompiler = default;
IDxcUtils* pUtils = default; IDxcUtils* pUtils = default;
ThrowIfFailed(DxcCreateInstance(&dxccID, __uuidof(pCompiler), (void**)&pCompiler));
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
_compiler.Attach(pCompiler);
_utils.Attach(pUtils);
}
public Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator, void** ppReflection)
{
// NOTE: Should we cache the _compiler.Get() and _utils.Get() instances for better performance?
IDxcIncludeHandler* pIncludeHandler = default; IDxcIncludeHandler* pIncludeHandler = default;
try try
{ {
// Create DXC pCompiler and pUtils // Create DXC _compiler.Get() and _utils.Get()
var dxccID = CLSID.CLSID_DxcCompiler; var dxccID = CLSID.CLSID_DxcCompiler;
var dxcuID = CLSID.CLSID_DxcUtils; var dxcuID = CLSID.CLSID_DxcUtils;
ThrowIfFailed(DxcCreateInstance(&dxccID, __uuidof(pCompiler), (void**)&pCompiler));
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
ThrowIfFailed(pUtils->CreateDefaultIncludeHandler(&pIncludeHandler)); ThrowIfFailed(_utils.Get()->CreateDefaultIncludeHandler(&pIncludeHandler));
// Create source blob // Create source blob
using ComPtr<IDxcBlobEncoding> sourceBlob = default; using ComPtr<IDxcBlobEncoding> sourceBlob = default;
fixed (char* pPath = config.shaderPath) fixed (char* pPath = config.shaderPath)
{ {
if (pUtils->LoadFile(pPath, null, sourceBlob.GetAddressOf()).FAILED) if (_utils.Get()->LoadFile(pPath, null, sourceBlob.GetAddressOf()).FAILED)
{ {
return Result.Fail($"Failed to load shader file: {config.shaderPath}"); return Result.Fail($"Failed to load shader file: {config.shaderPath}");
} }
@@ -197,7 +168,7 @@ internal static unsafe class D3D12ShaderCompiler
Encoding = DXC_CP_UTF8 Encoding = DXC_CP_UTF8
}; };
ThrowIfFailed(pCompiler->Compile(&buffer, argPtrs, (uint)argsArray.Count, pIncludeHandler, __uuidof(pResult), (void**)&pResult)); ThrowIfFailed(_compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, pIncludeHandler, __uuidof(pResult), (void**)&pResult));
// Check compilation pResult // Check compilation pResult
HRESULT hrStatus; HRESULT hrStatus;
@@ -224,9 +195,9 @@ internal static unsafe class D3D12ShaderCompiler
ThrowIfFailed(pResult->GetResult(bytecodeBlob.GetAddressOf())); ThrowIfFailed(pResult->GetResult(bytecodeBlob.GetAddressOf()));
// Get pReflection data using DXC API // Get pReflection data using DXC API
if (ppReflectionBlob != null) if (ppReflection != null)
{ {
ThrowIfFailed(pResult->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof<IDxcBlob>(), (void**)ppReflectionBlob, null)); ThrowIfFailed(pResult->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof<IDxcBlob>(), ppReflection, null));
} }
var bytecodeSize = bytecodeBlob.Get()->GetBufferSize(); var bytecodeSize = bytecodeBlob.Get()->GetBufferSize();
@@ -251,39 +222,37 @@ internal static unsafe class D3D12ShaderCompiler
} }
finally finally
{ {
pCompiler->Release();
pUtils->Release();
pIncludeHandler->Release(); pIncludeHandler->Release();
} }
} }
// TODO: Since we are using fixed root signature layout, the pReflection pass should only validate the layout, not generate it. // TODO: Since we are using fixed root signature layout, the pReflection pass should only validate the layout, not generate it.
// TODO: Ideally this should return a structured pReflection data instead of populating raw lists/dictionaries. // TODO: Ideally this should return a structured pReflection data instead of populating raw lists/dictionaries.
public static Result<ShaderReflectionData> PerformDXCReflection(IDxcBlob* reflectionBlob) public Result<ShaderReflectionData> PerformDXCReflection<T>(T* pReflectionBlob)
where T : unmanaged
{ {
if (reflectionBlob == null) if (typeof(T) != typeof(IDxcBlob))
{ {
return Result<ShaderReflectionData>.Fail("Reflection blob is null."); return Result<ShaderReflectionData>.Fail("Unsupported reflection type. Only IDxcBlob is supported.");
} }
IDxcUtils* pUtils = default;
ID3D12ShaderReflection* pReflection = default; ID3D12ShaderReflection* pReflection = default;
IDxcBlob* pDxcReflectionBlob = (IDxcBlob*)pReflectionBlob;
try try
{ {
// Create DXC pUtils to parse pReflection data // Create DXC _utils.Get() to parse pReflection data
var dxcuID = CLSID.CLSID_DxcUtils; var dxcuID = CLSID.CLSID_DxcUtils;
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
// Create pReflection interface from blob // Create pReflection interface from blob
var reflectionBuffer = new DxcBuffer var reflectionBuffer = new DxcBuffer
{ {
Ptr = reflectionBlob->GetBufferPointer(), Ptr = pDxcReflectionBlob->GetBufferPointer(),
Size = reflectionBlob->GetBufferSize(), Size = pDxcReflectionBlob->GetBufferSize(),
Encoding = DXC_CP_ACP Encoding = DXC_CP_ACP
}; };
ThrowIfFailed(pUtils->CreateReflection(&reflectionBuffer, __uuidof(pReflection), (void**)&pReflection)); ThrowIfFailed(_utils.Get()->CreateReflection(&reflectionBuffer, __uuidof(pReflection), (void**)&pReflection));
D3D12_SHADER_DESC shaderDesc; D3D12_SHADER_DESC shaderDesc;
ThrowIfFailed(pReflection->GetDesc(&shaderDesc)); ThrowIfFailed(pReflection->GetDesc(&shaderDesc));
@@ -301,6 +270,15 @@ internal static unsafe class D3D12ShaderCompiler
return Result.Fail("Failed to get resource name from reflection data."); return Result.Fail("Failed to get resource name from reflection data.");
} }
var info = new ResourceBindingInfo
{
Name = resourceName,
Type = ToInputType(bindDesc.Type),
BindPoint = bindDesc.BindPoint,
BindCount = bindDesc.BindCount,
Space = bindDesc.Space
};
switch (bindDesc.Type) switch (bindDesc.Type)
{ {
case D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER: case D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER:
@@ -332,41 +310,22 @@ internal static unsafe class D3D12ShaderCompiler
}); });
} }
reflectionData.ConstantBuffers.Add(new CBufferInfo info.Size = cbufferDesc.Size;
{ info.Properties = variables;
Name = resourceName,
RegisterSlot = bindDesc.BindPoint,
RegisterSpace = bindDesc.Space,
SizeInBytes = cbufferDesc.Size,
Properties = variables
});
break; break;
} }
// NOTE: Currently we do not support resource bindings yet, everything access through bindless heaps. // NOTE: Currently we do not support resource bindings yet, everything access through bindless heaps.
default: }
{
reflectionData.OtherResources.Add(new ResourceBindingInfo
{
Name = resourceName,
Type = bindDesc.Type,
BindPoint = bindDesc.BindPoint,
BindCount = bindDesc.BindCount,
Space = bindDesc.Space
});
break; reflectionData.ResourcesBindings.Add(info);
}
}
} }
return reflectionData; return reflectionData;
} }
finally finally
{ {
pUtils->Release();
pReflection->Release(); pReflection->Release();
} }
} }

View File

@@ -85,23 +85,36 @@ internal struct GraphicsPipelineHash
public TextureFormat rtvFormats; public TextureFormat rtvFormats;
} }
public ShaderPassKey id; public ShaderPassKey Id
public rtv_array rtvFormats; {
public uint rtvCount; get; set;
public TextureFormat dsvFormat; }
public rtv_array RtvFormats;
public uint RtvCount
{
get; set;
}
public TextureFormat DsvFormat
{
get; set;
}
// Do we need to store blend state? // Do we need to store blend state?
// TODO: Variants // TODO: Variants
public readonly GraphicsPipelineKey GetKey() public GraphicsPipelineKey GetKey()
{ {
Span<ulong> data = stackalloc ulong[3 + D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT]; Span<ulong> data = stackalloc ulong[3 + D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
data[0] = id.value; data[0] = Id.value;
data[1] = rtvCount; data[1] = RtvCount;
data[2] = (ulong)dsvFormat; data[2] = (ulong)DsvFormat;
for (var i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) for (var i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{ {
data[3 + i] = (ulong)rtvFormats[i]; data[3 + i] = (ulong)RtvFormats[i];
} }
var bytes = MemoryMarshal.AsBytes(data); var bytes = MemoryMarshal.AsBytes(data);
@@ -111,15 +124,46 @@ internal struct GraphicsPipelineHash
public ref struct GraphicsPSODescriptor public ref struct GraphicsPSODescriptor
{ {
public ShaderPassKey passId; public ShaderPassKey PassId
public ZTestOptions zTest; {
public ZWriteOptions zWrite; get; set;
public CullOptions cull; }
public BlendOptions blend;
public uint colorMask;
public ReadOnlySpan<TextureFormat> rtvFormats; public ZTestOptions ZTest
public TextureFormat dsvFormat; {
get; set;
}
public ZWriteOptions ZWrite
{
get; set;
}
public CullOptions Cull
{
get; set;
}
public BlendOptions Blend
{
get; set;
}
public uint ColorMask
{
get; set;
}
public ReadOnlySpan<TextureFormat> RtvFormats
{
get; set;
}
public TextureFormat DsvFormat
{
get; set;
}
} }
public readonly struct CBufferPropertyInfo public readonly struct CBufferPropertyInfo
@@ -170,20 +214,60 @@ public readonly struct CBufferInfo
public struct ViewportDesc public struct ViewportDesc
{ {
public float x; public float X
public float y; {
public float width; get; set;
public float height; }
public float minDepth;
public float maxDepth; public float Y
{
get; set;
}
public float Width
{
get; set;
}
public float Height
{
get; set;
}
public float MinDepth
{
get; set;
}
public float MaxDepth
{
get; set;
}
} }
public struct RectDesc public struct RectDesc
{ {
public uint left; public uint Left
public uint top; {
public uint right; get; set;
public uint bottom; }
public uint Top
{
get; set;
}
public uint Right
{
get; set;
}
public uint Bottom
{
get; set;
}
} }
public struct SubResourceData public struct SubResourceData
@@ -195,32 +279,68 @@ public struct SubResourceData
public struct PassRenderTargetDesc public struct PassRenderTargetDesc
{ {
public Handle<Texture> texture; public Handle<Texture> Texture
public Color128 clearColor; {
get; set;
}
public Color128 ClearColor
{
get; set;
}
} }
public struct PassDepthStencilDesc public struct PassDepthStencilDesc
{ {
public Handle<Texture> texture; public Handle<Texture> Texture
public float clearDepth; {
public byte clearStencil; get; set;
}
public float ClearDepth
{
get; set;
}
public byte ClearStencil
{
get; set;
}
} }
[StructLayout(LayoutKind.Explicit)]
public struct ResourceDesc public struct ResourceDesc
{
[StructLayout(LayoutKind.Explicit)]
private struct resource_union
{ {
[FieldOffset(0)] [FieldOffset(0)]
public TextureDesc textureDescription; public TextureDesc textureDescription;
[FieldOffset(0)] [FieldOffset(0)]
public BufferDesc bufferDescription; public BufferDesc bufferDescription;
}
private resource_union _desc;
public TextureDesc TextureDescription
{
readonly get => _desc.textureDescription;
set => _desc.textureDescription = value;
}
public BufferDesc BufferDescription
{
readonly get => _desc.bufferDescription;
set => _desc.bufferDescription = value;
}
public static ResourceDesc Buffer(BufferDesc desc) public static ResourceDesc Buffer(BufferDesc desc)
{ {
return new ResourceDesc return new ResourceDesc
{ {
bufferDescription = desc BufferDescription = desc
}; };
} }
@@ -228,7 +348,7 @@ public struct ResourceDesc
{ {
return new ResourceDesc return new ResourceDesc
{ {
textureDescription = desc TextureDescription = desc
}; };
} }
@@ -271,8 +391,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public uint Width public uint Width
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -280,8 +399,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public uint Height public uint Height
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -289,8 +407,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public uint Slice public uint Slice
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -298,8 +415,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public RenderTargetType Type public RenderTargetType Type
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -307,8 +423,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public TextureFormat Format public TextureFormat Format
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -316,8 +431,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public TextureDimension Dimension public TextureDimension Dimension
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -325,8 +439,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public RenderTargetCreationFlags CreationFlags public RenderTargetCreationFlags CreationFlags
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -334,8 +447,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public uint MipLevels public uint MipLevels
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -343,8 +455,7 @@ public struct RenderTargetDesc
/// </summary> /// </summary>
public uint SampleCount public uint SampleCount
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -423,8 +534,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public uint Width public uint Width
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -432,8 +542,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public uint Height public uint Height
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -441,8 +550,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public uint Slice public uint Slice
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -450,8 +558,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public TextureFormat Format public TextureFormat Format
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -468,8 +575,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public uint MipLevels public uint MipLevels
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -477,8 +583,7 @@ public struct TextureDesc
/// </summary> /// </summary>
public TextureUsage Usage public TextureUsage Usage
{ {
get; get; set;
set;
} }
} }
@@ -492,14 +597,12 @@ public struct BufferDesc
/// </summary> /// </summary>
public ulong Size public ulong Size
{ {
get; get; set;
set;
} }
public uint Stride public uint Stride
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -507,8 +610,7 @@ public struct BufferDesc
/// </summary> /// </summary>
public BufferUsage Usage public BufferUsage Usage
{ {
get; get; set;
set;
} }
/// <summary> /// <summary>
@@ -516,8 +618,7 @@ public struct BufferDesc
/// </summary> /// </summary>
public ResourceMemoryType MemoryType public ResourceMemoryType MemoryType
{ {
get; get; set;
set;
} }
} }
@@ -725,49 +826,3 @@ public enum PrimitiveTopology
Line, Line,
Triangle, Triangle,
} }
// SDL compiler
internal ref struct CompilerConfig
{
public ReadOnlySpan<string> defines;
public string? include;
public string shaderPath;
public string entryPoint;
public ShaderStage stage;
public CompilerTier tier;
public CompilerOptimizeLevel optimizeLevel;
public CompilerOption options;
}
internal enum CompilerTier
{
Tier0,
Tier1,
Tier2
}
internal enum CompilerOptimizeLevel
{
O0,
O1,
O2,
O3
}
[Flags]
internal enum CompilerOption
{
None = 0,
KeepDebugInfo = 1 << 0,
KeepReflections = 1 << 1,
WarnAsError = 1 << 2
}
internal enum ShaderStage
{
TaskShader,
MeshShader,
PixelShader,
ComputeShader
}

View File

@@ -0,0 +1,130 @@
using Ghost.Core;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
namespace Ghost.Graphics.RHI;
public struct CompileResult : IDisposable
{
public UnsafeArray<byte> bytecode;
public readonly bool IsCreated => bytecode.IsCreated;
public void Dispose()
{
bytecode.Dispose();
}
}
public ref struct CompilerConfig
{
public ReadOnlySpan<string> defines;
public string? include;
public string shaderPath;
public string entryPoint;
public ShaderStage stage;
public CompilerTier tier;
public CompilerOptimizeLevel optimizeLevel;
public CompilerOption options;
}
public enum CompilerTier
{
Tier0,
Tier1,
Tier2
}
public enum CompilerOptimizeLevel
{
O0,
O1,
O2,
O3
}
[Flags]
public enum CompilerOption
{
None = 0,
KeepDebugInfo = 1 << 0,
KeepReflections = 1 << 1,
WarnAsError = 1 << 2
}
public enum ShaderStage
{
TaskShader,
MeshShader,
PixelShader,
ComputeShader
}
public enum ShaderInputType
{
ConstantBuffer,
Texture,
Sampler,
UAV,
StructuredBuffer,
ByteAddressBuffer,
RWStructuredBuffer,
RWByteAddressBuffer
}
public struct ResourceBindingInfo
{
public string Name
{
get; set;
}
public ShaderInputType Type
{
get; set;
}
public uint BindPoint
{
get; set;
}
public uint BindCount
{
get; set;
}
public uint Space
{
get; set;
}
public uint Size
{
get; set;
}
public IReadOnlyList<CBufferPropertyInfo>? Properties
{
get; set;
}
}
public readonly struct ShaderReflectionData
{
public List<ResourceBindingInfo> ResourcesBindings
{
get;
}
public ShaderReflectionData()
{
ResourcesBindings = new List<ResourceBindingInfo>();
}
}
public unsafe interface IShaderCompiler
{
Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator, void** ppReflection);
Result<ShaderReflectionData> PerformDXCReflection<T>(T* pReflectionBlob) where T : unmanaged;
}

View File

@@ -47,7 +47,7 @@ public interface ISwapChain : IDisposable
/// <summary> /// <summary>
/// Resizes the swap chain back buffers /// Resizes the swap chain back buffers
/// </summary> /// </summary>
/// <param name="width">New width</param> /// <param name="width">New Width</param>
/// <param name="height">New height</param> /// <param name="height">New Height</param>
public void Resize(uint width, uint height); public void Resize(uint width, uint height);
} }

View File

@@ -27,8 +27,8 @@ void MSMain(
out indices uint3 outTris[1]) out indices uint3 outTris[1])
{ {
// Fetch bindless buffers // Fetch bindless buffers
ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerMaterialData.vertexBufferIndex]; ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerObjectData.vertexBuffer];
ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerMaterialData.indexBufferIndex]; ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerObjectData.indexBuffer];
// Compute the triangles vertex indices // Compute the triangles vertex indices
uint vertexId = groupThreadID.x; uint vertexId = groupThreadID.x;
@@ -46,6 +46,8 @@ void MSMain(
SetMeshOutputCounts(3, 1); SetMeshOutputCounts(3, 1);
v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
// Write vertex output // Write vertex output
outVerts[vertexId].position = v.position; outVerts[vertexId].position = v.position;
outVerts[vertexId].color = v.color; outVerts[vertexId].color = v.color;

View File

@@ -7,8 +7,6 @@ shader "MyShader/Standard"
tex2d_b texture2 = tex2d_b(white); tex2d_b texture2 = tex2d_b(white);
tex2d_b texture3 = tex2d_b(grey); tex2d_b texture3 = tex2d_b(grey);
tex2d_b texture4 = tex2d_b(normal); tex2d_b texture4 = tex2d_b(normal);
uint vertexBufferIndex;
uint indexBufferIndex;
} }
pipeline pipeline

View File

@@ -6,6 +6,7 @@
struct PerViewData struct PerViewData
{ {
float4x4 cameraMatrix; float4x4 cameraMatrix;
float4x4 cameraInverseMatrix;
float4 screenSize; // xy = size, zw = 1/size float4 screenSize; // xy = size, zw = 1/size
}; };