diff --git a/.gitignore b/.gitignore
index 9491a2f..52d9dd1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ bld/
# Visual Studio 2015/2017 cache/options directory
.vs/
+.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 72fd640..0000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "Build Ghost.Graphics with RenderGraph",
- "type": "shell",
- "command": "dotnet",
- "args": [
- "build",
- "Ghost.Graphics/Ghost.Graphics.csproj",
- "-c",
- "Debug"
- ],
- "group": "build",
- "problemMatcher": [
- "$msCompile"
- ],
- "isBackground": false
- }
- ]
-}
\ No newline at end of file
diff --git a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
index f2d4102..5cf4f09 100644
--- a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
+++ b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
@@ -117,6 +117,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
throw new NotImplementedException();
}
+ // TODO: Batch draw calls by material to minimize state changes
public void DrawMesh(Mesh mesh, Material material)
{
// Bind the bindless material (sets up root signature, pipeline state, and descriptor heaps)
diff --git a/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs b/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
index cd7cec6..286689f 100644
--- a/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
+++ b/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
@@ -1,5 +1,8 @@
using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
+using Ghost.Graphics.Data;
+using Ghost.Graphics.RHI;
+using System.Runtime.CompilerServices;
using Win32.Graphics.Direct3D12;
namespace Ghost.Graphics.D3D12;
@@ -7,13 +10,13 @@ namespace Ghost.Graphics.D3D12;
///
/// D3D12 implementation of descriptor allocator that manages different types of descriptor heaps.
///
-internal unsafe class D3D12DescriptorAllocator : IDisposable
+internal unsafe class D3D12DescriptorAllocator : IDescriptorAllocator, IDisposable
{
- private readonly DescriptorHeapAllocator _rtvHeap;
- private readonly DescriptorHeapAllocator _dsvHeap;
- private readonly DescriptorHeapAllocator _srvHeap;
- private readonly DescriptorHeapAllocator _samplerHeap;
- private readonly BindlessDescriptorHeapAllocator _bindlessHeap;
+ private readonly D3D12DescriptorHeap _rtvHeap;
+ private readonly D3D12DescriptorHeap _dsvHeap;
+ private readonly D3D12DescriptorHeap _srvHeap;
+ private readonly D3D12DescriptorHeap _samplerHeap;
+ private readonly BindlessDescriptorHeap _bindlessHeap;
private bool _disposed;
@@ -21,11 +24,11 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
{
var pDevice = device.NativeDevice;
- _rtvHeap = new DescriptorHeapAllocator("rtv", pDevice, DescriptorHeapType.Rtv, initialRtvCount);
- _dsvHeap = new DescriptorHeapAllocator("dsv", pDevice, DescriptorHeapType.Dsv, initialDsvCount);
- _srvHeap = new DescriptorHeapAllocator("srv", pDevice, DescriptorHeapType.CbvSrvUav, initialSrvCount);
- _samplerHeap = new DescriptorHeapAllocator("sampler", pDevice, DescriptorHeapType.Sampler, initialSamplerCount);
- _bindlessHeap = new BindlessDescriptorHeapAllocator(pDevice, initialBindlessCount);
+ _rtvHeap = new D3D12DescriptorHeap("rtv", pDevice, DescriptorHeapType.Rtv, initialRtvCount);
+ _dsvHeap = new D3D12DescriptorHeap("dsv", pDevice, DescriptorHeapType.Dsv, initialDsvCount);
+ _srvHeap = new D3D12DescriptorHeap("srv", pDevice, DescriptorHeapType.CbvSrvUav, initialSrvCount);
+ _samplerHeap = new D3D12DescriptorHeap("sampler", pDevice, DescriptorHeapType.Sampler, initialSamplerCount);
+ _bindlessHeap = new BindlessDescriptorHeap(pDevice, initialBindlessCount);
}
~D3D12DescriptorAllocator()
@@ -45,8 +48,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate RTV descriptor");
}
- var cpuHandle = _rtvHeap.GetCpuHandle(index);
- return new RenderTargetDescriptor(index, cpuHandle);
+ return new RenderTargetDescriptor { Index = index };
}
public RenderTargetDescriptor[] AllocateRTVs(uint count)
@@ -63,30 +65,33 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
for (uint i = 0; i < count; i++)
{
var index = baseIndex + i;
- var cpuHandle = _rtvHeap.GetCpuHandle(index);
- descriptors[i] = new RenderTargetDescriptor(index, cpuHandle);
+ descriptors[i] = new RenderTargetDescriptor { Index = index };
}
return descriptors;
}
- public void ReleaseRTV(RenderTargetDescriptor descriptor)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CpuDescriptorHandle GetCpuHandle(RenderTargetDescriptor descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (descriptor is RenderTargetDescriptor d3d12Descriptor)
- {
- _rtvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
- }
+ return _rtvHeap.GetCpuHandle(descriptor.Index);
}
- public void ReleaseRTVs(RenderTargetDescriptor[] descriptors)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Release(RenderTargetDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ _rtvHeap.ReleaseDescriptor(descriptor.Index);
+ }
+
+ public void Release(ReadOnlySpan descriptors)
{
ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors)
{
- ReleaseRTV(descriptor);
+ Release(descriptor);
}
}
@@ -104,8 +109,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate DSV descriptor");
}
- var cpuHandle = _dsvHeap.GetCpuHandle(index);
- return new DepthStencilDescriptor(index, cpuHandle);
+ return new DepthStencilDescriptor { Index = index };
}
public DepthStencilDescriptor[] AllocateDSVs(uint count)
@@ -122,30 +126,31 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
for (uint i = 0; i < count; i++)
{
var index = baseIndex + i;
- var cpuHandle = _dsvHeap.GetCpuHandle(index);
- descriptors[i] = new DepthStencilDescriptor(index, cpuHandle);
+ descriptors[i] = new DepthStencilDescriptor { Index = index };
}
return descriptors;
}
- public void ReleaseDSV(DepthStencilDescriptor descriptor)
+ public CpuDescriptorHandle GetCpuHandle(DepthStencilDescriptor descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (descriptor is DepthStencilDescriptor d3d12Descriptor)
- {
- _dsvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
- }
+ return _dsvHeap.GetCpuHandle(descriptor.Index);
}
- public void ReleaseDSVs(DepthStencilDescriptor[] descriptors)
+ public void Release(DepthStencilDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ _dsvHeap.ReleaseDescriptor(descriptor.Index);
+ }
+
+ public void Release(ReadOnlySpan descriptors)
{
ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors)
{
- ReleaseDSV(descriptor);
+ Release(descriptor);
}
}
@@ -163,13 +168,8 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate SRV descriptor");
}
- var cpuHandle = _srvHeap.GetCpuHandle(index);
- var gpuHandle = _srvHeap.GetGpuHandle(index);
-
- // Copy to shader visible heap
_srvHeap.CopyToShaderVisibleHeap(index);
-
- return new ShaderResourceDescriptor(index, cpuHandle, gpuHandle);
+ return new ShaderResourceDescriptor { Index = index };
}
public ShaderResourceDescriptor[] AllocateSRVs(uint count)
@@ -186,34 +186,38 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
for (uint i = 0; i < count; i++)
{
var index = baseIndex + i;
- var cpuHandle = _srvHeap.GetCpuHandle(index);
- var gpuHandle = _srvHeap.GetGpuHandle(index);
- descriptors[i] = new ShaderResourceDescriptor(index, cpuHandle, gpuHandle);
+ descriptors[i] = new ShaderResourceDescriptor { Index = index };
}
- // Copy all descriptors to shader visible heap
_srvHeap.CopyToShaderVisibleHeap(baseIndex, count);
-
return descriptors;
}
- public void ReleaseSRV(ShaderResourceDescriptor descriptor)
+ public CpuDescriptorHandle GetCpuHandle(ShaderResourceDescriptor descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (descriptor is ShaderResourceDescriptor d3d12Descriptor)
- {
- _srvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
- }
+ return _srvHeap.GetCpuHandle(descriptor.Index);
}
- public void ReleaseSRVs(ShaderResourceDescriptor[] descriptors)
+ public GpuDescriptorHandle GetGpuHandle(ShaderResourceDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ return _srvHeap.GetGpuHandle(descriptor.Index);
+ }
+
+ public void Release(ShaderResourceDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ _srvHeap.ReleaseDescriptor(descriptor.Index);
+ }
+
+ public void Release(ReadOnlySpan descriptors)
{
ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors)
{
- ReleaseSRV(descriptor);
+ Release(descriptor);
}
}
@@ -231,13 +235,8 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate Sampler descriptor");
}
- var cpuHandle = _samplerHeap.GetCpuHandle(index);
- var gpuHandle = _samplerHeap.GetGpuHandle(index);
-
- // Copy to shader visible heap
_samplerHeap.CopyToShaderVisibleHeap(index);
-
- return new SamplerDescriptor(index, cpuHandle, gpuHandle);
+ return new SamplerDescriptor { Index = index };
}
public SamplerDescriptor[] AllocateSamplers(uint count)
@@ -254,34 +253,38 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
for (uint i = 0; i < count; i++)
{
var index = baseIndex + i;
- var cpuHandle = _samplerHeap.GetCpuHandle(index);
- var gpuHandle = _samplerHeap.GetGpuHandle(index);
- descriptors[i] = new SamplerDescriptor(index, cpuHandle, gpuHandle);
+ descriptors[i] = new SamplerDescriptor { Index = index };
}
- // Copy all descriptors to shader visible heap
_samplerHeap.CopyToShaderVisibleHeap(baseIndex, count);
-
return descriptors;
}
- public void ReleaseSampler(SamplerDescriptor descriptor)
+ public CpuDescriptorHandle GetCpuHandle(SamplerDescriptor descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (descriptor is SamplerDescriptor d3d12Descriptor)
- {
- _samplerHeap.ReleaseDescriptor(d3d12Descriptor.Index);
- }
+ return _samplerHeap.GetCpuHandle(descriptor.Index);
}
- public void ReleaseSamplers(SamplerDescriptor[] descriptors)
+ public GpuDescriptorHandle GetGpuHandle(SamplerDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ return _samplerHeap.GetGpuHandle(descriptor.Index);
+ }
+
+ public void Release(SamplerDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ _samplerHeap.ReleaseDescriptor(descriptor.Index);
+ }
+
+ public void Release(ReadOnlySpan descriptors)
{
ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors)
{
- ReleaseSampler(descriptor);
+ Release(descriptor);
}
}
@@ -303,10 +306,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate bindless descriptor");
}
- var cpuHandle = _bindlessHeap.GetCpuHandle(index);
- var gpuHandle = _bindlessHeap.GetGpuHandle(index);
-
- return new BindlessDescriptor(index, cpuHandle, gpuHandle);
+ return new BindlessDescriptor { Index = index };
}
///
@@ -326,37 +326,43 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
for (uint i = 0; i < count; i++)
{
var index = baseIndex + i;
- var cpuHandle = _bindlessHeap.GetCpuHandle(index);
- var gpuHandle = _bindlessHeap.GetGpuHandle(index);
- descriptors[i] = new BindlessDescriptor(index, cpuHandle, gpuHandle);
+ descriptors[i] = new BindlessDescriptor { Index = index };
}
return descriptors;
}
+ public CpuDescriptorHandle GetCpuHandle(BindlessDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ return _bindlessHeap.GetCpuHandle(descriptor.Index);
+ }
+
+ public GpuDescriptorHandle GetGpuHandle(BindlessDescriptor descriptor)
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ return _bindlessHeap.GetGpuHandle(descriptor.Index);
+ }
+
///
/// Releases a bindless descriptor.
///
- public void ReleaseBindless(BindlessDescriptor descriptor)
+ public void Release(BindlessDescriptor descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (descriptor is BindlessDescriptor d3d12Descriptor)
- {
- _bindlessHeap.ReleaseDescriptor(d3d12Descriptor.Index);
- }
+ _bindlessHeap.ReleaseDescriptor(descriptor.Index);
}
///
/// Releases multiple bindless descriptors.
///
- public void ReleaseBindless(BindlessDescriptor[] descriptors)
+ public void Release(ReadOnlySpan descriptors)
{
ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors)
{
- ReleaseBindless(descriptor);
+ Release(descriptor);
}
}
diff --git a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
index 60ab9a4..73c9ca4 100644
--- a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
+++ b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
@@ -9,16 +9,16 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
#endif
private readonly D3D12RenderDevice _device;
- private readonly D3D12PipelineStateController _stateController;
+ private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly D3D12ResourceAllocator _resourceAllocator;
- private readonly D3D12PipelineStateController _pipelineState;
- private readonly D3D12DescriptorAllocator _descriptorAllocator;
+ private readonly D3D12PipelineStateController _stateController;
public IRenderDevice Device => _device;
- public IPipelineStateController PipelineStateController => _stateController;
public IResourceAllocator ResourceAllocator => _resourceAllocator;
+ public IPipelineStateController PipelineStateController => _stateController;
+
public D3D12GraphicsEngine(RenderSystem renderSystem)
{
#if DEBUG
@@ -26,11 +26,10 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
#endif
_device = new();
- _stateController = new(_device);
- _resourceAllocator = new(_device, renderSystem);
-
- _pipelineState = new(_device);
_descriptorAllocator = new(_device);
+ _resourceAllocator = new(renderSystem, _device, _descriptorAllocator);
+
+ _stateController = new(_device);
}
public IRenderer CreateRenderer()
@@ -50,6 +49,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
public void Dispose()
{
+ _stateController.Dispose();
_descriptorAllocator.Dispose();
_resourceAllocator.Dispose();
_device.Dispose();
diff --git a/Ghost.Graphics/D3D12/D3D12PipelineStateController.cs b/Ghost.Graphics/D3D12/D3D12PipelineStateController.cs
index fc5e770..29aca4b 100644
--- a/Ghost.Graphics/D3D12/D3D12PipelineStateController.cs
+++ b/Ghost.Graphics/D3D12/D3D12PipelineStateController.cs
@@ -25,10 +25,6 @@ internal class D3D12ShaderPipeline : IShaderPipeline
internal unsafe class D3D12PipelineStateController : IPipelineStateController, IDisposable
{
- private const string _VS_ENTRY_POINT = "VSMain";
- private const string _PS_ENTRY_POINT = "PSMain";
- private const string _PROFILE_VS_6_6 = "vs_6_6";
-
private readonly ID3D12Device14* _device;
private readonly Dictionary _shaderPipelines;
@@ -55,8 +51,8 @@ internal unsafe class D3D12PipelineStateController : IPipelineStateController, I
{
foreach (var kvp in _shaderPipelines)
{
- var vsResult = D3D12ShaderCompiler.CompileDXC(kvp.Key, _VS_ENTRY_POINT, _PROFILE_VS_6_6);
- var psResult = D3D12ShaderCompiler.CompileDXC(kvp.Key, _PS_ENTRY_POINT, _PROFILE_VS_6_6);
+ var vsResult = D3D12ShaderCompiler.Compile(kvp.Key, D3D12ShaderCompiler.ShaderStage.VertexShader, D3D12ShaderCompiler.CompilerVersion.SM_6_6);
+ var psResult = D3D12ShaderCompiler.Compile(kvp.Key, D3D12ShaderCompiler.ShaderStage.PixelShader, D3D12ShaderCompiler.CompilerVersion.SM_6_6);
kvp.Value.vsResult = vsResult;
kvp.Value.psResult = psResult;
diff --git a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
index 489bd66..ae2962e 100644
--- a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
+++ b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
@@ -7,7 +7,6 @@ using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi;
using Win32.Graphics.Dxgi.Common;
using static Win32.Graphics.D3D12MemoryAllocator.Apis;
-using ResourceHandle = Ghost.Graphics.Data.ResourceHandle;
namespace Ghost.Graphics.D3D12;
@@ -43,8 +42,12 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
private UnsafeQueue _freeSlots = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
private UnsafeQueue _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
@@ -60,10 +63,8 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocatorCreateShaderResourceView(allocation.Resource, &srvDesc, _descriptorAllocator.GetCpuHandle(descriptorHandle));
+
+ return new(handle, descriptorHandle);
+ }
+
+ return new(handle);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferHandle CreateUploadBuffer(uint sizeInBytes, bool tempResource = false)
{
- var desc = new BufferDesc(sizeInBytes, BufferUsage.Upload, MemoryType.Upload);
+ var desc = new BufferDesc
+ {
+ Size = sizeInBytes,
+ Usage = BufferUsage.Upload,
+ MemoryType = MemoryType.Upload
+ };
+
return CreateBufferHandle(in desc, tempResource);
}
diff --git a/Ghost.Graphics/D3D12/D3D12ShaderCompiler.cs b/Ghost.Graphics/D3D12/D3D12ShaderCompiler.cs
index c5c1df8..b0c0a9e 100644
--- a/Ghost.Graphics/D3D12/D3D12ShaderCompiler.cs
+++ b/Ghost.Graphics/D3D12/D3D12ShaderCompiler.cs
@@ -11,6 +11,20 @@ namespace Ghost.Graphics.D3D12;
internal unsafe static class D3D12ShaderCompiler
{
+ public enum CompilerVersion
+ {
+ SM_6_6,
+ SM_7_0
+ }
+
+ public enum ShaderStage
+ {
+ VertexShader,
+ PixelShader,
+ MeshShader,
+ ComputeShader
+ }
+
public struct CompileResult : IDisposable
{
public UnsafeArray bytecode;
@@ -23,7 +37,35 @@ internal unsafe static class D3D12ShaderCompiler
}
}
- public static CompileResult CompileDXC(Shader shader, string entryPoint, string profile)
+ private static string GetProfileString(ShaderStage stage, CompilerVersion version)
+ {
+ return (stage, version) switch
+ {
+ (ShaderStage.VertexShader, CompilerVersion.SM_6_6) => "vs_6_6",
+ (ShaderStage.PixelShader, CompilerVersion.SM_6_6) => "ps_6_6",
+ (ShaderStage.MeshShader, CompilerVersion.SM_6_6) => "ms_6_6",
+ (ShaderStage.ComputeShader, CompilerVersion.SM_6_6) => "cs_6_6",
+ (ShaderStage.VertexShader, CompilerVersion.SM_7_0) => "vs_7_0",
+ (ShaderStage.PixelShader, CompilerVersion.SM_7_0) => "ps_7_0",
+ (ShaderStage.MeshShader, CompilerVersion.SM_7_0) => "ms_7_0",
+ (ShaderStage.ComputeShader, CompilerVersion.SM_7_0) => "cs_7_0",
+ _ => throw new ArgumentOutOfRangeException(nameof(stage), "Unsupported shader stage or compiler version")
+ };
+ }
+
+ private static string GetEntryPoint(ShaderStage stage)
+ {
+ return stage switch
+ {
+ ShaderStage.VertexShader => "VSMain",
+ ShaderStage.PixelShader => "PSMain",
+ ShaderStage.MeshShader => "MSMain",
+ ShaderStage.ComputeShader => "CSMain",
+ _ => throw new ArgumentOutOfRangeException(nameof(stage), "Unsupported shader stage")
+ };
+ }
+
+ public static CompileResult Compile(Shader shader, ShaderStage stage, CompilerVersion version)
{
using ComPtr compiler = default;
using ComPtr utils = default;
@@ -43,12 +85,12 @@ internal unsafe static class D3D12ShaderCompiler
// Prepare compilation arguments - NOTE: NO -Qstrip_reflect to keep reflection data
var argsArray = new string[]
{
- "-T", profile, // Target profile (vs_6_6, ps_6_6)
- "-E", entryPoint, // Entry point
- "-HV", "2021", // HLSL version 2021 (required for SM 6.6)
- "-enable-16bit-types", // Enable 16-bit types
- "-O3", // Optimization level
- "-Qstrip_debug" // Strip debug info but KEEP reflection
+ "-T", GetProfileString(stage, version), // Target profile (vs_6_6, ps_6_6)
+ "-E", GetEntryPoint(stage), // Entry point
+ "-HV", "2021", // HLSL version 2021 (required for SM 6.6)
+ "-enable-16bit-types", // Enable 16-bit types
+ "-O3", // Optimization level
+ "-Qstrip_debug" // Strip debug info but KEEP reflection
};
// Convert to wide strings (DXC expects LPCWSTR)
diff --git a/Ghost.Graphics/D3D12/Descriptors.cs b/Ghost.Graphics/D3D12/Descriptors.cs
deleted file mode 100644
index 54a7a76..0000000
--- a/Ghost.Graphics/D3D12/Descriptors.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using Win32.Graphics.Direct3D12;
-
-namespace Ghost.Graphics.D3D12;
-
-///
-/// Implementation of render target view (RTV) descriptor.
-///
-public readonly struct RenderTargetDescriptor
-{
- public uint Index
- {
- get;
- }
-
- public CpuDescriptorHandle CpuHandle
- {
- get;
- }
-
- public RenderTargetDescriptor(uint index, CpuDescriptorHandle cpuHandle)
- {
- Index = index;
- CpuHandle = cpuHandle;
- }
-}
-
-///
-/// Implementation of depth stencil view (DSV) descriptor.
-///
-public readonly struct DepthStencilDescriptor
-{
- public uint Index
- {
- get;
- }
-
- public CpuDescriptorHandle CpuHandle
- {
- get;
- }
-
- public DepthStencilDescriptor(uint index, CpuDescriptorHandle cpuHandle)
- {
- Index = index;
- CpuHandle = cpuHandle;
- }
-}
-
-///
-/// Implementation of shader resource view (SRV) descriptor.
-///
-public sealed class ShaderResourceDescriptor
-{
- public uint Index
- {
- get;
- }
-
- public CpuDescriptorHandle CpuHandle
- {
- get;
- }
-
- public GpuDescriptorHandle GpuHandle
- {
- get;
- }
-
- public ShaderResourceDescriptor(uint index, CpuDescriptorHandle cpuHandle, GpuDescriptorHandle gpuHandle)
- {
- Index = index;
- CpuHandle = cpuHandle;
- GpuHandle = gpuHandle;
- }
-}
-
-///
-/// Implementation of sampler descriptor.
-///
-public sealed class SamplerDescriptor
-{
- public uint Index
- {
- get;
- }
-
- public CpuDescriptorHandle CpuHandle
- {
- get;
- }
-
- public GpuDescriptorHandle GpuHandle
- {
- get;
- }
-
- public SamplerDescriptor(uint index, CpuDescriptorHandle cpuHandle, GpuDescriptorHandle gpuHandle)
- {
- Index = index;
- CpuHandle = cpuHandle;
- GpuHandle = gpuHandle;
- }
-}
-
-///
-/// Implementation of bindless descriptor for SM 6.6 rendering.
-/// This descriptor maintains a 1:1 relationship between allocation indices and shader indices.
-///
-public sealed class BindlessDescriptor
-{
- public uint Index
- {
- get;
- }
-
- public CpuDescriptorHandle CpuHandle
- {
- get;
- }
-
- public GpuDescriptorHandle GpuHandle
- {
- get;
- }
-
- public BindlessDescriptor(uint index, CpuDescriptorHandle cpuHandle, GpuDescriptorHandle gpuHandle)
- {
- Index = index;
- CpuHandle = cpuHandle;
- GpuHandle = gpuHandle;
- }
-}
\ No newline at end of file
diff --git a/Ghost.Graphics/D3D12/Renderer.cs b/Ghost.Graphics/D3D12/Renderer.cs
index dd674d2..0cae5d5 100644
--- a/Ghost.Graphics/D3D12/Renderer.cs
+++ b/Ghost.Graphics/D3D12/Renderer.cs
@@ -64,7 +64,7 @@ internal unsafe class Renderer
commandAllocator.Dispose();
commandList.Dispose();
backBuffer.Dispose();
- GraphicsPipeline.DescriptorAllocator.ReleaseRTV(rtvDescriptor);
+ GraphicsPipeline.DescriptorAllocator.Release(rtvDescriptor);
}
}
@@ -226,7 +226,7 @@ internal unsafe class Renderer
if (frameResource.backBuffer.Get() is not null)
{
var c = frameResource.backBuffer.Reset();
- GraphicsPipeline.DescriptorAllocator.ReleaseRTV(frameResource.rtvDescriptor);
+ GraphicsPipeline.DescriptorAllocator.Release(frameResource.rtvDescriptor);
}
frameResource.fenceValue = _frameResources[_backBufferIndex].fenceValue;
diff --git a/Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeapAllocator.cs b/Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeap.cs
similarity index 88%
rename from Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeapAllocator.cs
rename to Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeap.cs
index 9c48053..24ea516 100644
--- a/Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeapAllocator.cs
+++ b/Ghost.Graphics/D3D12/Utilities/BindlessDescriptorHeap.cs
@@ -10,7 +10,7 @@ namespace Ghost.Graphics.D3D12.Utilities;
/// Specialized descriptor heap allocator for SM 6.6 bindless rendering with ResourceDescriptorHeap[index].
/// This allocator maintains a 1:1 relationship between allocation indices and shader indices.
///
-internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
+internal unsafe struct BindlessDescriptorHeap : IDisposable
{
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
@@ -42,7 +42,7 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
public readonly ConstPtr BindlessHeap => new(_bindlessHeap.Get());
- public BindlessDescriptorHeapAllocator(ComPtr device, uint numDescriptors = 10000)
+ public BindlessDescriptorHeap(ComPtr device, uint numDescriptors = 10000)
{
_device = device;
device.Get()->AddRef();
@@ -67,7 +67,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
// Try to grow the heap
if (!Grow(NumDescriptors * 2))
{
- Debug.WriteLine("ERROR: Failed to grow bindless descriptor heap!");
return _INVALID_DESCRIPTOR_INDEX;
}
}
@@ -88,7 +87,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
var newSize = Math.Max(NumDescriptors * 2, NumDescriptors + count);
if (!Grow(newSize))
{
- Debug.WriteLine("ERROR: Failed to grow bindless descriptor heap!");
return _INVALID_DESCRIPTOR_INDEX;
}
}
@@ -110,7 +108,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
{
if (index >= NumDescriptors)
{
- Debug.WriteLine("Error: Attempted to release an invalid descriptor index");
return;
}
@@ -128,7 +125,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
var index = baseIndex + i;
if (index >= NumDescriptors)
{
- Debug.WriteLine("Error: Attempted to release an invalid descriptor index");
continue;
}
@@ -139,19 +135,19 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
}
}
- public CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
+ public readonly CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
{
var handle = _startCpuHandle;
return handle.Offset((int)index, _stride);
}
- public GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
+ public readonly GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
{
var handle = _startGpuHandle;
return handle.Offset((int)index, _stride);
}
- public GpuDescriptorHandle GetGpuHandleStart()
+ public readonly GpuDescriptorHandle GetGpuHandleStart()
{
return _startGpuHandle;
}
diff --git a/Ghost.Graphics/D3D12/Utilities/DescriptorHeapAllocator.cs b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
similarity index 81%
rename from Ghost.Graphics/D3D12/Utilities/DescriptorHeapAllocator.cs
rename to Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
index 1e88778..b9a4980 100644
--- a/Ghost.Graphics/D3D12/Utilities/DescriptorHeapAllocator.cs
+++ b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
@@ -6,11 +6,11 @@ using DescriptorIndex = System.UInt32;
namespace Ghost.Graphics.D3D12.Utilities;
-internal unsafe struct DescriptorHeapAllocator : IDisposable
+internal unsafe struct D3D12DescriptorHeap : IDisposable
{
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
- private ComPtr _device;
+ private readonly ID3D12Device14* _pDevice;
private ComPtr _heap;
private ComPtr _shaderVisibleHeap;
@@ -50,15 +50,14 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
- public DescriptorHeapAllocator(string name, ComPtr device, DescriptorHeapType type, uint numDescriptors)
+ public D3D12DescriptorHeap(string name, ID3D12Device14* device, DescriptorHeapType type, uint numDescriptors)
{
- _device = device;
- device.Get()->AddRef();
+ _pDevice = device;
HeapType = type;
NumDescriptors = numDescriptors;
ShaderVisible = type == DescriptorHeapType.CbvSrvUav || type == DescriptorHeapType.Sampler;
- Stride = device.Get()->GetDescriptorHandleIncrementSize(type);
+ Stride = device->GetDescriptorHandleIncrementSize(type);
var success = AllocateResources(numDescriptors);
Debug.Assert(success);
@@ -154,27 +153,27 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
}
}
- public CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
+ public readonly CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
{
var handle = _startCpuHandle;
return handle.Offset((int)index, Stride);
}
- public CpuDescriptorHandle GetCpuHandleShaderVisible(DescriptorIndex index)
+ public readonly CpuDescriptorHandle GetCpuHandleShaderVisible(DescriptorIndex index)
{
var handle = _startCpuHandleShaderVisible;
return handle.Offset((int)index, Stride);
}
- public GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
+ public readonly GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
{
var handle = _startGpuHandleShaderVisible;
return handle.Offset((int)index, Stride);
}
- public void CopyToShaderVisibleHeap(DescriptorIndex index, uint count = 1)
+ public readonly void CopyToShaderVisibleHeap(DescriptorIndex index, uint count = 1)
{
- _device.Get()->CopyDescriptorsSimple(count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
+ _pDevice->CopyDescriptorsSimple(count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
}
private bool AllocateResources(uint numDescriptors)
@@ -193,7 +192,7 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
fixed (void* heapPtr = &_heap)
{
- var hr = _device.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(), (void**)heapPtr);
+ var hr = _pDevice->CreateDescriptorHeap(&heapDesc, __uuidof(), (void**)heapPtr);
if (hr.Failure)
{
return false;
@@ -209,7 +208,7 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
fixed (void* heapPtr = &_shaderVisibleHeap)
{
- var hr = _device.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(), (void**)heapPtr);
+ var hr = _pDevice->CreateDescriptorHeap(&heapDesc, __uuidof(), (void**)heapPtr);
if (hr.Failure)
{
return false;
@@ -235,11 +234,11 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
return false;
}
- _device.Get()->CopyDescriptorsSimple(oldSize, _startCpuHandle, oldHeap.Get()->GetCPUDescriptorHandleForHeapStart(), HeapType);
+ _pDevice->CopyDescriptorsSimple(oldSize, _startCpuHandle, oldHeap.Get()->GetCPUDescriptorHandleForHeapStart(), HeapType);
if (_shaderVisibleHeap.Get() is not null)
{
- _device.Get()->CopyDescriptorsSimple(oldSize, _startCpuHandleShaderVisible, oldHeap.Get()->GetCPUDescriptorHandleForHeapStart(), HeapType);
+ _pDevice->CopyDescriptorsSimple(oldSize, _startCpuHandleShaderVisible, oldHeap.Get()->GetCPUDescriptorHandleForHeapStart(), HeapType);
}
return true;
@@ -248,8 +247,6 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
///
public void Dispose()
{
- _device.Dispose();
-
_heap.Dispose();
_shaderVisibleHeap.Dispose();
}
diff --git a/Ghost.Graphics/Data/Descriptors.cs b/Ghost.Graphics/Data/Descriptors.cs
new file mode 100644
index 0000000..63d849f
--- /dev/null
+++ b/Ghost.Graphics/Data/Descriptors.cs
@@ -0,0 +1,78 @@
+using Win32.Graphics.Direct3D12;
+
+namespace Ghost.Graphics.Data;
+
+///
+/// Render target view (RTV) descriptor.
+///
+public readonly struct RenderTargetDescriptor
+{
+ public uint Index
+ {
+ get; init;
+ }
+
+ public static RenderTargetDescriptor Invalid => new() { Index = ~0u };
+
+ public bool IsValid => Index != ~0u;
+}
+
+///
+/// Depth stencil view (DSV) descriptor.
+///
+public readonly struct DepthStencilDescriptor
+{
+ public uint Index
+ {
+ get; init;
+ }
+
+ public static DepthStencilDescriptor Invalid => new() { Index = ~0u };
+
+ public bool IsValid => Index != ~0u;
+}
+
+///
+/// Shader resource view (SRV) descriptor.
+///
+public readonly struct ShaderResourceDescriptor
+{
+ public uint Index
+ {
+ get; init;
+ }
+
+ public static ShaderResourceDescriptor Invalid => new() { Index = ~0u };
+
+ public bool IsValid => Index != ~0u;
+}
+
+///
+/// Sampler descriptor.
+///
+public readonly struct SamplerDescriptor
+{
+ public uint Index
+ {
+ get; init;
+ }
+
+ public static SamplerDescriptor Invalid => new() { Index = ~0u };
+
+ public bool IsValid => Index != ~0u;
+}
+
+///
+/// Bindless descriptor
+///
+public readonly struct BindlessDescriptor
+{
+ public uint Index
+ {
+ get; init;
+ }
+
+ public static BindlessDescriptor Invalid => new() { Index = ~0u };
+
+ public bool IsValid => Index != ~0u;
+}
\ No newline at end of file
diff --git a/Ghost.Graphics/Data/Mesh.cs b/Ghost.Graphics/Data/Mesh.cs
index 31ccbe6..0994579 100644
--- a/Ghost.Graphics/Data/Mesh.cs
+++ b/Ghost.Graphics/Data/Mesh.cs
@@ -1,4 +1,5 @@
using Ghost.Graphics.D3D12;
+using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Helpers;
@@ -9,18 +10,15 @@ using Win32.Graphics.Dxgi.Common;
namespace Ghost.Graphics.Data;
-public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialIndexCapacity = 512) : IDisposable
+public unsafe sealed class Mesh : IDisposable
{
- private UnsafeList _vertices = new(initialVertexCapacity, Allocator.Persistent);
- private UnsafeList _indices = new(initialIndexCapacity, Allocator.Persistent);
+ private UnsafeList _vertices;
+ private UnsafeList _indices;
private Bounds _boundingBox;
- private GraphicsBuffer? _vertexBuffer;
- private GraphicsBuffer? _indexBuffer;
-
- private BindlessDescriptor? _vertexBufferDescriptor;
- private BindlessDescriptor? _indexBufferDescriptor;
+ private IBuffer? _vertexBuffer;
+ private IBuffer? _indexBuffer;
public Span Vertices => _vertices.AsSpan();
public Span Indices => _indices.AsSpan();
@@ -29,8 +27,59 @@ public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialInde
public uint VertexCount => (uint)_vertices.Count;
public uint IndexCount => (uint)_indices.Count;
- public uint VertexBufferDescriptorIndex => _vertexBufferDescriptor?.Index ?? throw new InvalidOperationException("Vertex buffer descriptor is not allocated.");
- public uint IndexBufferDescriptorIndex => _indexBufferDescriptor?.Index ?? throw new InvalidOperationException("Index buffer descriptor is not allocated.");
+ public uint VertexBufferDescriptorIndex
+ {
+ get
+ {
+ if (_vertexBuffer == null || !_vertexBuffer.Handle.IsValid)
+ {
+ throw new InvalidOperationException("Vertex buffer is not created.");
+ }
+
+ var bindlessDesc = _vertexBuffer.Handle.BindlessDescriptor;
+ if (!bindlessDesc.IsValid)
+ {
+ throw new InvalidOperationException("Vertex buffer is not created with bindless.");
+ }
+
+ return bindlessDesc.Index;
+ }
+ }
+
+ public uint IndexBufferDescriptorIndex
+ {
+ get
+ {
+ if (_indexBuffer == null || !_indexBuffer.Handle.IsValid)
+ {
+ throw new InvalidOperationException("Index buffer is not created.");
+ }
+
+ var bindlessDesc = _indexBuffer.Handle.BindlessDescriptor;
+ if (!bindlessDesc.IsValid)
+ {
+ throw new InvalidOperationException("Index buffer is not created with bindless.");
+ }
+
+ return bindlessDesc.Index;
+ }
+ }
+
+ public Mesh(int initialVertexCapacity = 256, int initialIndexCapacity = 512)
+ {
+ _vertices = new(initialVertexCapacity, Allocator.Persistent);
+ _indices = new(initialIndexCapacity, Allocator.Persistent);
+ }
+
+ public Mesh(ReadOnlySpan vertices, ReadOnlySpan indices)
+ : this(vertices.Length, indices.Length)
+ {
+ _vertices = new(vertices.Length, Allocator.Persistent);
+ _indices = new(indices.Length, Allocator.Persistent);
+
+ _vertices.CopyFrom(vertices);
+ _indices.CopyFrom(indices);
+ }
~Mesh()
{
@@ -302,6 +351,13 @@ public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialInde
device->CreateShaderResourceView(_indexBuffer.NativeResource.Ptr, &indexSrvDesc, _indexBufferDescriptor.CpuHandle);
}
+
+ internal void MarkNoLongerReadable()
+ {
+ _vertices.Dispose();
+ _indices.Dispose();
+ }
+
///
/// Clears all vertex and index data and releases associated GPU resources.
///
@@ -320,14 +376,14 @@ public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialInde
_indexBuffer?.Dispose();
_indexBuffer = null;
- if (_vertexBufferDescriptor != null)
+ if (_vertexBufferDescriptor.IsValid)
{
- GraphicsPipeline.DescriptorAllocator.ReleaseBindless(_vertexBufferDescriptor);
+ RenderSystem.GraphicsEngine.DescriptorAllocator.Release(_vertexBufferDescriptor);
}
- if (_indexBufferDescriptor != null)
+ if (_indexBufferDescriptor.IsValid)
{
- GraphicsPipeline.DescriptorAllocator.ReleaseBindless(_indexBufferDescriptor);
+ RenderSystem.GraphicsEngine.DescriptorAllocator.Release(_indexBufferDescriptor);
}
}
diff --git a/Ghost.Graphics/Data/ResourceHandle.cs b/Ghost.Graphics/Data/ResourceHandle.cs
index a7e4a58..cf251f1 100644
--- a/Ghost.Graphics/Data/ResourceHandle.cs
+++ b/Ghost.Graphics/Data/ResourceHandle.cs
@@ -3,7 +3,7 @@ using Win32.Graphics.D3D12MemoryAllocator;
namespace Ghost.Graphics.Data;
-public readonly struct ResourceHandle : IEquatable, IDisposable
+public readonly struct ResourceHandle : IEquatable
{
private const int _INVALID_ID = -1;
@@ -20,17 +20,6 @@ public readonly struct ResourceHandle : IEquatable, IDisposable
public bool IsValid => id != _INVALID_ID && generation >= 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Allocation GetAllocation()
- {
- if (!IsValid)
- {
- throw new InvalidOperationException("Cannot get allocation from an invalid AllocationHandle.");
- }
-
- return GraphicsPipeline.ResourceAllocator.GetResource(this);
- }
-
public bool Equals(ResourceHandle other)
{
return id == other.id && generation == other.generation;
@@ -49,21 +38,6 @@ public readonly struct ResourceHandle : IEquatable, IDisposable
return obj is ResourceHandle handle && Equals(handle);
}
- public void Dispose()
- {
- GraphicsPipeline.ResourceAllocator.ReleaseResource(this);
- }
-
- public static implicit operator Allocation(ResourceHandle handle)
- {
- if (!handle.IsValid)
- {
- throw new InvalidOperationException("Cannot convert an invalid AllocationHandle to Allocation.");
- }
-
- return handle.GetAllocation();
- }
-
public static bool operator ==(ResourceHandle left, ResourceHandle right)
{
return left.Equals(right);
@@ -75,7 +49,7 @@ public readonly struct ResourceHandle : IEquatable, IDisposable
}
}
-public readonly struct TextureHandle : IEquatable, IDisposable
+public readonly struct TextureHandle : IEquatable
{
private readonly ResourceHandle _resourceHandle;
@@ -104,11 +78,6 @@ public readonly struct TextureHandle : IEquatable, IDisposable
return _resourceHandle.GetHashCode();
}
- public void Dispose()
- {
- _resourceHandle.Dispose();
- }
-
public static bool operator ==(TextureHandle left, TextureHandle right)
{
return left.Equals(right);
@@ -120,16 +89,26 @@ public readonly struct TextureHandle : IEquatable, IDisposable
}
}
-public readonly struct BufferHandle : IEquatable, IDisposable
+public readonly struct BufferHandle : IEquatable
{
private readonly ResourceHandle _resourceHandle;
+ private readonly BindlessDescriptor _bindlessDescriptor;
+
+ public static BufferHandle Invalid => new(ResourceHandle.Invalid);
public ResourceHandle ResourceHandle => _resourceHandle;
- public static BufferHandle Invalid => new(ResourceHandle.Invalid);
+ public BindlessDescriptor BindlessDescriptor => _bindlessDescriptor;
internal BufferHandle(ResourceHandle resourceHandle)
{
_resourceHandle = resourceHandle;
+ _bindlessDescriptor = BindlessDescriptor.Invalid;
+ }
+
+ internal BufferHandle(ResourceHandle resourceHandle, BindlessDescriptor descriptor)
+ {
+ _resourceHandle = resourceHandle;
+ _bindlessDescriptor = descriptor;
}
public bool IsValid => _resourceHandle.IsValid;
@@ -149,11 +128,6 @@ public readonly struct BufferHandle : IEquatable, IDisposable
return _resourceHandle.GetHashCode();
}
- public void Dispose()
- {
- _resourceHandle.Dispose();
- }
-
public static bool operator ==(BufferHandle left, BufferHandle right)
{
return left.Equals(right);
diff --git a/Ghost.Graphics/Data/Shader.cs b/Ghost.Graphics/Data/Shader.cs
index 28cc2a0..b7eabb2 100644
--- a/Ghost.Graphics/Data/Shader.cs
+++ b/Ghost.Graphics/Data/Shader.cs
@@ -60,10 +60,10 @@ internal readonly struct CBufferInfo
}
///
-/// Bindless shader implementation using SM 6.6 with ResourceDescriptorHeap
-/// and D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED
-/// Enhanced to support both bindless and regular texture binding for hybrid materials
+/// A representation of a GPU shader, including its metadata about its resources.
///
+
+// TODO: Multi pass and keyword support
public unsafe class Shader : IDisposable
{
private readonly string _source;
@@ -82,6 +82,7 @@ public unsafe class Shader : IDisposable
internal List RegularTextures => _regularTextures;
internal Dictionary PropertyNameToIdMap => _propertyNameToIdMap;
+ // TODO: In real production, we should not load the shader source code directly.
internal Shader(string shaderCode)
{
_source = shaderCode;
diff --git a/Ghost.Graphics/Data/Texture.cs b/Ghost.Graphics/Data/Texture.cs
index ab7569a..a603a25 100644
--- a/Ghost.Graphics/Data/Texture.cs
+++ b/Ghost.Graphics/Data/Texture.cs
@@ -142,6 +142,6 @@ public abstract unsafe class Texture : GraphicsResource
public override void Dispose()
{
base.Dispose();
- GraphicsPipeline.DescriptorAllocator.ReleaseBindless(_bindlessDescriptor);
+ GraphicsPipeline.DescriptorAllocator.Release(_bindlessDescriptor);
}
}
\ No newline at end of file
diff --git a/Ghost.Graphics/Data/Texture2D.cs b/Ghost.Graphics/Data/Texture2D.cs
index b0dd519..388412d 100644
--- a/Ghost.Graphics/Data/Texture2D.cs
+++ b/Ghost.Graphics/Data/Texture2D.cs
@@ -1,4 +1,3 @@
-using Ghost.Graphics.D3D12;
using Misaki.HighPerformance.Image;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
diff --git a/Ghost.Graphics/RHI/ICommandQueue.cs b/Ghost.Graphics/RHI/ICommandQueue.cs
index 91a506c..583e09b 100644
--- a/Ghost.Graphics/RHI/ICommandQueue.cs
+++ b/Ghost.Graphics/RHI/ICommandQueue.cs
@@ -1,7 +1,7 @@
namespace Ghost.Graphics.RHI;
///
-/// D3D12-style command queue interface
+/// Command queue interface
///
public interface ICommandQueue : IDisposable
{
@@ -46,7 +46,7 @@ public interface ICommandQueue : IDisposable
}
///
-/// Command queue types matching D3D12
+/// Command queue types
///
public enum CommandQueueType
{
diff --git a/Ghost.Graphics/RHI/IDescriptorAllocator.cs b/Ghost.Graphics/RHI/IDescriptorAllocator.cs
new file mode 100644
index 0000000..b25c945
--- /dev/null
+++ b/Ghost.Graphics/RHI/IDescriptorAllocator.cs
@@ -0,0 +1,64 @@
+using Ghost.Graphics.Data;
+using System.Runtime.CompilerServices;
+using Win32.Graphics.Direct3D12;
+
+namespace Ghost.Graphics.RHI;
+
+public interface IDescriptorAllocator
+{
+ public RenderTargetDescriptor AllocateRTV();
+
+ public RenderTargetDescriptor[] AllocateRTVs(uint count);
+
+ public DepthStencilDescriptor AllocateDSV();
+
+ public DepthStencilDescriptor[] AllocateDSVs(uint count);
+
+ public ShaderResourceDescriptor AllocateSRV();
+
+ public ShaderResourceDescriptor[] AllocateSRVs(uint count);
+
+ public SamplerDescriptor AllocateSampler();
+
+ public SamplerDescriptor[] AllocateSamplers(uint count);
+
+ public BindlessDescriptor AllocateBindless();
+
+ public BindlessDescriptor[] AllocateBindless(uint count);
+
+ public CpuDescriptorHandle GetCpuHandle(RenderTargetDescriptor descriptor);
+
+ public CpuDescriptorHandle GetCpuHandle(DepthStencilDescriptor descriptor);
+
+ public CpuDescriptorHandle GetCpuHandle(ShaderResourceDescriptor descriptor);
+
+ public GpuDescriptorHandle GetGpuHandle(ShaderResourceDescriptor descriptor);
+
+ public CpuDescriptorHandle GetCpuHandle(SamplerDescriptor descriptor);
+
+ public GpuDescriptorHandle GetGpuHandle(SamplerDescriptor descriptor);
+
+ public CpuDescriptorHandle GetCpuHandle(BindlessDescriptor descriptor);
+
+ public GpuDescriptorHandle GetGpuHandle(BindlessDescriptor descriptor);
+
+ public void Release(RenderTargetDescriptor descriptor);
+
+ public void Release(ReadOnlySpan descriptors);
+
+ public void Release(DepthStencilDescriptor descriptor);
+
+ public void Release(ReadOnlySpan descriptors);
+
+ public void Release(ShaderResourceDescriptor descriptor);
+
+ public void Release(ReadOnlySpan descriptors);
+
+ public void Release(SamplerDescriptor descriptor);
+
+ public void Release(ReadOnlySpan descriptors);
+
+ public void Release(BindlessDescriptor descriptor);
+
+ public void Release(ReadOnlySpan descriptors);
+}
\ No newline at end of file
diff --git a/Ghost.Graphics/RHI/IRenderTypes.cs b/Ghost.Graphics/RHI/IRenderTypes.cs
index 279d68b..79beb1e 100644
--- a/Ghost.Graphics/RHI/IRenderTypes.cs
+++ b/Ghost.Graphics/RHI/IRenderTypes.cs
@@ -165,7 +165,16 @@ public struct RenderTargetDesc
usage |= TextureUsage.UnorderedAccess;
}
- return new TextureDesc(desc.Width, desc.Height, desc.Slice, desc.Format, desc.Dimension, desc.MipLevels, usage);
+ return new TextureDesc
+ {
+ Width = desc.Width,
+ Height = desc.Height,
+ Slice = desc.Slice,
+ Format = desc.Format,
+ Dimension = desc.Dimension,
+ MipLevels = desc.MipLevels,
+ Usage = usage
+ };
}
}
@@ -236,19 +245,6 @@ public struct TextureDesc
get;
set;
}
-
- public TextureDesc(uint width, uint height, uint slice = 1,
- TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D,
- uint mipLevels = 0u, TextureUsage usage = TextureUsage.ShaderResource)
- {
- Width = width;
- Height = height;
- Slice = slice;
- Format = format;
- Dimension = dimension;
- MipLevels = mipLevels;
- Usage = usage;
- }
}
///
@@ -265,6 +261,12 @@ public struct BufferDesc
set;
}
+ public uint Stride
+ {
+ get;
+ set;
+ }
+
///
/// Buffer usage flags
///
@@ -274,6 +276,12 @@ public struct BufferDesc
set;
}
+ public BufferCreationFlags CreationFlags
+ {
+ get;
+ set;
+ }
+
///
/// Memory type for the buffer
///
@@ -282,13 +290,6 @@ public struct BufferDesc
get;
set;
}
-
- public BufferDesc(ulong size, BufferUsage usage, MemoryType memoryType = MemoryType.Default)
- {
- Size = size;
- Usage = usage;
- MemoryType = memoryType;
- }
}
///
diff --git a/Ghost.Graphics/RHI/IResource.cs b/Ghost.Graphics/RHI/IResource.cs
index 6aca2f8..c0f8910 100644
--- a/Ghost.Graphics/RHI/IResource.cs
+++ b/Ghost.Graphics/RHI/IResource.cs
@@ -1,3 +1,5 @@
+using Ghost.Graphics.Data;
+
namespace Ghost.Graphics.RHI;
///
@@ -8,17 +10,26 @@ public interface IResource : IDisposable
///
/// Current resource state
///
- ResourceState CurrentState { get; }
+ ResourceState CurrentState
+ {
+ get;
+ }
///
/// Resource name for debugging
///
- string Name { get; set; }
+ string Name
+ {
+ get; set;
+ }
///
/// Size of the resource in bytes
///
- ulong Size { get; }
+ ulong Size
+ {
+ get;
+ }
}
///
@@ -29,22 +40,34 @@ public interface ITexture : IResource
///
/// Width of the texture in pixels
///
- uint Width { get; }
+ uint Width
+ {
+ get;
+ }
///
/// Height of the texture in pixels
///
- uint Height { get; }
+ uint Height
+ {
+ get;
+ }
///
/// Texture format
///
- TextureFormat Format { get; }
+ TextureFormat Format
+ {
+ get;
+ }
///
/// Number of mip levels
///
- uint MipLevels { get; }
+ uint MipLevels
+ {
+ get;
+ }
}
///
@@ -55,18 +78,26 @@ public interface IBuffer : IResource
///
/// Buffer usage type
///
- BufferUsage Usage { get; }
+ public BufferUsage Usage
+ {
+ get;
+ }
+
+ public BufferHandle Handle
+ {
+ get;
+ }
///
/// Maps the buffer for CPU access
///
/// Pointer to mapped memory
- unsafe void* Map();
+ public unsafe void* Map();
///
/// Unmaps the buffer from CPU access
///
- void Unmap();
+ public void Unmap();
}
///
@@ -78,7 +109,10 @@ public interface IRenderTarget : ITexture
///
/// Type of render target (color or depth)
///
- RenderTargetType Type { get; }
+ RenderTargetType Type
+ {
+ get;
+ }
}
///
@@ -117,5 +151,15 @@ public enum BufferUsage
Structured = 1 << 3,
Raw = 1 << 4,
Upload = 1 << 5,
- Readback = 1 << 6
+ Readback = 1 << 6,
+ IndirectArgument = 1 << 7,
+
+ ShaderResource = Vertex | Index | Constant
}
+
+[Flags]
+public enum BufferCreationFlags
+{
+ None = 0,
+ Bindless = 1 << 0
+}
\ No newline at end of file
diff --git a/Ghost.Graphics/RenderSystem.cs b/Ghost.Graphics/RenderSystem.cs
index 7d5075a..ecd12ac 100644
--- a/Ghost.Graphics/RenderSystem.cs
+++ b/Ghost.Graphics/RenderSystem.cs
@@ -12,7 +12,7 @@ public enum GraphicsAPI
/// Application-level render system that orchestrates multiple renderers
/// and handles frame synchronization
///
-internal class RenderSystem : IDisposable
+internal class RenderSystem
{
private readonly struct FrameResource : IDisposable
{
@@ -34,15 +34,16 @@ internal class RenderSystem : IDisposable
private const uint _FRAME_COUNT = 2;
- private readonly IGraphicsEngine _engine;
- private readonly FrameResource[] _frameResources;
- private readonly Thread _renderThread;
- private readonly AutoResetEvent _shutdownEvent;
+ private readonly IGraphicsEngine _engine = null!;
+ private readonly FrameResource[] _frameResources = null!;
+ private readonly Thread _renderThread = null!;
+ private readonly AutoResetEvent _shutdownEvent = null!;
private ImmutableArray _renderers;
private uint _frameIndex;
private uint _cpuFenceValue;
private uint _gpuFenceValue;
+
private bool _isRunning;
private bool _disposed;
@@ -59,7 +60,7 @@ internal class RenderSystem : IDisposable
_ => throw new NotSupportedException($"Graphics API {api} is not supported.")
};
- _renderers = new();
+ _renderers = ImmutableArray.Empty;
_shutdownEvent = new(false);
// Create frame resources for synchronization
@@ -75,15 +76,14 @@ internal class RenderSystem : IDisposable
Name = "Graphics Render Thread",
Priority = ThreadPriority.Normal
};
- }
- ~RenderSystem()
- {
- Dispose();
+ _disposed = true;
}
public IRenderer CreateRenderer()
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
var renderer = _engine.CreateRenderer();
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Add(renderer));
return renderer;
@@ -91,11 +91,15 @@ internal class RenderSystem : IDisposable
public void RemoveRenderer(IRenderer renderer)
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Remove(renderer));
}
public void Start()
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
if (_isRunning)
{
return;
@@ -107,6 +111,8 @@ internal class RenderSystem : IDisposable
public void Stop()
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
if (!_isRunning)
{
return;
@@ -123,12 +129,16 @@ internal class RenderSystem : IDisposable
public bool WaitForGPUReady(int timeOut = -1)
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
return _frameResources[eventIndex].gpuReadyEvent.WaitOne(timeOut);
}
public void SignalCPUReady()
{
+ ObjectDisposedException.ThrowIf(_disposed, this);
+
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
_frameResources[eventIndex].cpuReadyEvent.Set();
_cpuFenceValue++;
@@ -184,7 +194,5 @@ internal class RenderSystem : IDisposable
_shutdownEvent.Dispose();
_disposed = true;
-
- GC.SuppressFinalize(this);
}
}