Refactor descriptor handling and shader compilation
Refactored descriptor allocation and release logic by introducing `IDescriptorAllocator` and replacing `DescriptorHeapAllocator` with `D3D12DescriptorHeap`. Updated descriptor structs to include validation properties and improved memory management with `ReadOnlySpan`. Enhanced shader compilation by introducing `ShaderStage` and `CompilerVersion` enums, enabling more flexible and maintainable shader handling. Refactored `Mesh` to use `IBuffer` for vertex and index buffers, added bindless descriptor support, and improved resource cleanup. Updated `RenderSystem` and other components for better initialization, error handling, and disposal logic. General improvements to code readability and maintainability.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,6 +35,7 @@ bld/
|
|||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
.vscode/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
#wwwroot/
|
#wwwroot/
|
||||||
|
|
||||||
|
|||||||
21
.vscode/tasks.json
vendored
21
.vscode/tasks.json
vendored
@@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -117,6 +117,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Batch draw calls by material to minimize state changes
|
||||||
public void DrawMesh(Mesh mesh, Material material)
|
public void DrawMesh(Mesh mesh, Material material)
|
||||||
{
|
{
|
||||||
// Bind the bindless material (sets up root signature, pipeline state, and descriptor heaps)
|
// Bind the bindless material (sets up root signature, pipeline state, and descriptor heaps)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
|
using Ghost.Graphics.Data;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Win32.Graphics.Direct3D12;
|
using Win32.Graphics.Direct3D12;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
@@ -7,13 +10,13 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12 implementation of descriptor allocator that manages different types of descriptor heaps.
|
/// D3D12 implementation of descriptor allocator that manages different types of descriptor heaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class D3D12DescriptorAllocator : IDisposable
|
internal unsafe class D3D12DescriptorAllocator : IDescriptorAllocator, IDisposable
|
||||||
{
|
{
|
||||||
private readonly DescriptorHeapAllocator _rtvHeap;
|
private readonly D3D12DescriptorHeap _rtvHeap;
|
||||||
private readonly DescriptorHeapAllocator _dsvHeap;
|
private readonly D3D12DescriptorHeap _dsvHeap;
|
||||||
private readonly DescriptorHeapAllocator _srvHeap;
|
private readonly D3D12DescriptorHeap _srvHeap;
|
||||||
private readonly DescriptorHeapAllocator _samplerHeap;
|
private readonly D3D12DescriptorHeap _samplerHeap;
|
||||||
private readonly BindlessDescriptorHeapAllocator _bindlessHeap;
|
private readonly BindlessDescriptorHeap _bindlessHeap;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -21,11 +24,11 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
{
|
{
|
||||||
var pDevice = device.NativeDevice;
|
var pDevice = device.NativeDevice;
|
||||||
|
|
||||||
_rtvHeap = new DescriptorHeapAllocator("rtv", pDevice, DescriptorHeapType.Rtv, initialRtvCount);
|
_rtvHeap = new D3D12DescriptorHeap("rtv", pDevice, DescriptorHeapType.Rtv, initialRtvCount);
|
||||||
_dsvHeap = new DescriptorHeapAllocator("dsv", pDevice, DescriptorHeapType.Dsv, initialDsvCount);
|
_dsvHeap = new D3D12DescriptorHeap("dsv", pDevice, DescriptorHeapType.Dsv, initialDsvCount);
|
||||||
_srvHeap = new DescriptorHeapAllocator("srv", pDevice, DescriptorHeapType.CbvSrvUav, initialSrvCount);
|
_srvHeap = new D3D12DescriptorHeap("srv", pDevice, DescriptorHeapType.CbvSrvUav, initialSrvCount);
|
||||||
_samplerHeap = new DescriptorHeapAllocator("sampler", pDevice, DescriptorHeapType.Sampler, initialSamplerCount);
|
_samplerHeap = new D3D12DescriptorHeap("sampler", pDevice, DescriptorHeapType.Sampler, initialSamplerCount);
|
||||||
_bindlessHeap = new BindlessDescriptorHeapAllocator(pDevice, initialBindlessCount);
|
_bindlessHeap = new BindlessDescriptorHeap(pDevice, initialBindlessCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D12DescriptorAllocator()
|
~D3D12DescriptorAllocator()
|
||||||
@@ -45,8 +48,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
throw new InvalidOperationException("Failed to allocate RTV descriptor");
|
throw new InvalidOperationException("Failed to allocate RTV descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuHandle = _rtvHeap.GetCpuHandle(index);
|
return new RenderTargetDescriptor { Index = index };
|
||||||
return new RenderTargetDescriptor(index, cpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderTargetDescriptor[] AllocateRTVs(uint count)
|
public RenderTargetDescriptor[] AllocateRTVs(uint count)
|
||||||
@@ -63,30 +65,33 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
for (uint i = 0; i < count; i++)
|
for (uint i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
var cpuHandle = _rtvHeap.GetCpuHandle(index);
|
descriptors[i] = new RenderTargetDescriptor { Index = index };
|
||||||
descriptors[i] = new RenderTargetDescriptor(index, cpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseRTV(RenderTargetDescriptor descriptor)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public CpuDescriptorHandle GetCpuHandle(RenderTargetDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _rtvHeap.GetCpuHandle(descriptor.Index);
|
||||||
if (descriptor is RenderTargetDescriptor d3d12Descriptor)
|
|
||||||
{
|
|
||||||
_rtvHeap.ReleaseDescriptor(d3d12Descriptor.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<RenderTargetDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var descriptor in descriptors)
|
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");
|
throw new InvalidOperationException("Failed to allocate DSV descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuHandle = _dsvHeap.GetCpuHandle(index);
|
return new DepthStencilDescriptor { Index = index };
|
||||||
return new DepthStencilDescriptor(index, cpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DepthStencilDescriptor[] AllocateDSVs(uint count)
|
public DepthStencilDescriptor[] AllocateDSVs(uint count)
|
||||||
@@ -122,30 +126,31 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
for (uint i = 0; i < count; i++)
|
for (uint i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
var cpuHandle = _dsvHeap.GetCpuHandle(index);
|
descriptors[i] = new DepthStencilDescriptor { Index = index };
|
||||||
descriptors[i] = new DepthStencilDescriptor(index, cpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseDSV(DepthStencilDescriptor descriptor)
|
public CpuDescriptorHandle GetCpuHandle(DepthStencilDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _dsvHeap.GetCpuHandle(descriptor.Index);
|
||||||
if (descriptor is DepthStencilDescriptor d3d12Descriptor)
|
|
||||||
{
|
|
||||||
_dsvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseDSVs(DepthStencilDescriptor[] descriptors)
|
public void Release(DepthStencilDescriptor descriptor)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
_dsvHeap.ReleaseDescriptor(descriptor.Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release(ReadOnlySpan<DepthStencilDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var descriptor in descriptors)
|
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");
|
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);
|
_srvHeap.CopyToShaderVisibleHeap(index);
|
||||||
|
return new ShaderResourceDescriptor { Index = index };
|
||||||
return new ShaderResourceDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderResourceDescriptor[] AllocateSRVs(uint count)
|
public ShaderResourceDescriptor[] AllocateSRVs(uint count)
|
||||||
@@ -186,34 +186,38 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
for (uint i = 0; i < count; i++)
|
for (uint i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
var cpuHandle = _srvHeap.GetCpuHandle(index);
|
descriptors[i] = new ShaderResourceDescriptor { Index = index };
|
||||||
var gpuHandle = _srvHeap.GetGpuHandle(index);
|
|
||||||
descriptors[i] = new ShaderResourceDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all descriptors to shader visible heap
|
|
||||||
_srvHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
_srvHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseSRV(ShaderResourceDescriptor descriptor)
|
public CpuDescriptorHandle GetCpuHandle(ShaderResourceDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _srvHeap.GetCpuHandle(descriptor.Index);
|
||||||
if (descriptor is ShaderResourceDescriptor d3d12Descriptor)
|
|
||||||
{
|
|
||||||
_srvHeap.ReleaseDescriptor(d3d12Descriptor.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<ShaderResourceDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var descriptor in descriptors)
|
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");
|
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);
|
_samplerHeap.CopyToShaderVisibleHeap(index);
|
||||||
|
return new SamplerDescriptor { Index = index };
|
||||||
return new SamplerDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SamplerDescriptor[] AllocateSamplers(uint count)
|
public SamplerDescriptor[] AllocateSamplers(uint count)
|
||||||
@@ -254,34 +253,38 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
for (uint i = 0; i < count; i++)
|
for (uint i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
var cpuHandle = _samplerHeap.GetCpuHandle(index);
|
descriptors[i] = new SamplerDescriptor { Index = index };
|
||||||
var gpuHandle = _samplerHeap.GetGpuHandle(index);
|
|
||||||
descriptors[i] = new SamplerDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all descriptors to shader visible heap
|
|
||||||
_samplerHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
_samplerHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseSampler(SamplerDescriptor descriptor)
|
public CpuDescriptorHandle GetCpuHandle(SamplerDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _samplerHeap.GetCpuHandle(descriptor.Index);
|
||||||
if (descriptor is SamplerDescriptor d3d12Descriptor)
|
|
||||||
{
|
|
||||||
_samplerHeap.ReleaseDescriptor(d3d12Descriptor.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<SamplerDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var descriptor in descriptors)
|
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");
|
throw new InvalidOperationException("Failed to allocate bindless descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuHandle = _bindlessHeap.GetCpuHandle(index);
|
return new BindlessDescriptor { Index = index };
|
||||||
var gpuHandle = _bindlessHeap.GetGpuHandle(index);
|
|
||||||
|
|
||||||
return new BindlessDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -326,37 +326,43 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
for (uint i = 0; i < count; i++)
|
for (uint i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
var cpuHandle = _bindlessHeap.GetCpuHandle(index);
|
descriptors[i] = new BindlessDescriptor { Index = index };
|
||||||
var gpuHandle = _bindlessHeap.GetGpuHandle(index);
|
|
||||||
descriptors[i] = new BindlessDescriptor(index, cpuHandle, gpuHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases a bindless descriptor.
|
/// Releases a bindless descriptor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ReleaseBindless(BindlessDescriptor descriptor)
|
public void Release(BindlessDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
_bindlessHeap.ReleaseDescriptor(descriptor.Index);
|
||||||
if (descriptor is BindlessDescriptor d3d12Descriptor)
|
|
||||||
{
|
|
||||||
_bindlessHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases multiple bindless descriptors.
|
/// Releases multiple bindless descriptors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ReleaseBindless(BindlessDescriptor[] descriptors)
|
public void Release(ReadOnlySpan<BindlessDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var descriptor in descriptors)
|
foreach (var descriptor in descriptors)
|
||||||
{
|
{
|
||||||
ReleaseBindless(descriptor);
|
Release(descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12PipelineStateController _stateController;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
private readonly D3D12ResourceAllocator _resourceAllocator;
|
private readonly D3D12ResourceAllocator _resourceAllocator;
|
||||||
|
|
||||||
private readonly D3D12PipelineStateController _pipelineState;
|
private readonly D3D12PipelineStateController _stateController;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
|
||||||
|
|
||||||
public IRenderDevice Device => _device;
|
public IRenderDevice Device => _device;
|
||||||
public IPipelineStateController PipelineStateController => _stateController;
|
|
||||||
public IResourceAllocator ResourceAllocator => _resourceAllocator;
|
public IResourceAllocator ResourceAllocator => _resourceAllocator;
|
||||||
|
|
||||||
|
public IPipelineStateController PipelineStateController => _stateController;
|
||||||
|
|
||||||
public D3D12GraphicsEngine(RenderSystem renderSystem)
|
public D3D12GraphicsEngine(RenderSystem renderSystem)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -26,11 +26,10 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_device = new();
|
_device = new();
|
||||||
_stateController = new(_device);
|
|
||||||
_resourceAllocator = new(_device, renderSystem);
|
|
||||||
|
|
||||||
_pipelineState = new(_device);
|
|
||||||
_descriptorAllocator = new(_device);
|
_descriptorAllocator = new(_device);
|
||||||
|
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator);
|
||||||
|
|
||||||
|
_stateController = new(_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRenderer CreateRenderer()
|
public IRenderer CreateRenderer()
|
||||||
@@ -50,6 +49,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_stateController.Dispose();
|
||||||
_descriptorAllocator.Dispose();
|
_descriptorAllocator.Dispose();
|
||||||
_resourceAllocator.Dispose();
|
_resourceAllocator.Dispose();
|
||||||
_device.Dispose();
|
_device.Dispose();
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ internal class D3D12ShaderPipeline : IShaderPipeline
|
|||||||
|
|
||||||
internal unsafe class D3D12PipelineStateController : IPipelineStateController, IDisposable
|
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 ID3D12Device14* _device;
|
||||||
|
|
||||||
private readonly Dictionary<Shader, D3D12ShaderPipeline> _shaderPipelines;
|
private readonly Dictionary<Shader, D3D12ShaderPipeline> _shaderPipelines;
|
||||||
@@ -55,8 +51,8 @@ internal unsafe class D3D12PipelineStateController : IPipelineStateController, I
|
|||||||
{
|
{
|
||||||
foreach (var kvp in _shaderPipelines)
|
foreach (var kvp in _shaderPipelines)
|
||||||
{
|
{
|
||||||
var vsResult = D3D12ShaderCompiler.CompileDXC(kvp.Key, _VS_ENTRY_POINT, _PROFILE_VS_6_6);
|
var vsResult = D3D12ShaderCompiler.Compile(kvp.Key, D3D12ShaderCompiler.ShaderStage.VertexShader, D3D12ShaderCompiler.CompilerVersion.SM_6_6);
|
||||||
var psResult = D3D12ShaderCompiler.CompileDXC(kvp.Key, _PS_ENTRY_POINT, _PROFILE_VS_6_6);
|
var psResult = D3D12ShaderCompiler.Compile(kvp.Key, D3D12ShaderCompiler.ShaderStage.PixelShader, D3D12ShaderCompiler.CompilerVersion.SM_6_6);
|
||||||
|
|
||||||
kvp.Value.vsResult = vsResult;
|
kvp.Value.vsResult = vsResult;
|
||||||
kvp.Value.psResult = psResult;
|
kvp.Value.psResult = psResult;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Win32.Graphics.Direct3D12;
|
|||||||
using Win32.Graphics.Dxgi;
|
using Win32.Graphics.Dxgi;
|
||||||
using Win32.Graphics.Dxgi.Common;
|
using Win32.Graphics.Dxgi.Common;
|
||||||
using static Win32.Graphics.D3D12MemoryAllocator.Apis;
|
using static Win32.Graphics.D3D12MemoryAllocator.Apis;
|
||||||
using ResourceHandle = Ghost.Graphics.Data.ResourceHandle;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
@@ -43,8 +42,12 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
private const uint _MAX_TEXTURE2D_DIMENSION = 16384u;
|
private const uint _MAX_TEXTURE2D_DIMENSION = 16384u;
|
||||||
private const uint _MAX_TEXTURE3D_DIMENSION = 2048u;
|
private const uint _MAX_TEXTURE3D_DIMENSION = 2048u;
|
||||||
|
|
||||||
private readonly RenderSystem _renderSystem;
|
private readonly ID3D12Device14* _device;
|
||||||
|
|
||||||
private readonly Allocator _allocator;
|
private readonly Allocator _allocator;
|
||||||
|
private readonly RenderSystem _renderSystem;
|
||||||
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
|
|
||||||
private UnsafeList<AllocationInfo> _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
private UnsafeList<AllocationInfo> _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
private UnsafeQueue<int> _freeSlots = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
private UnsafeQueue<int> _freeSlots = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
private UnsafeQueue<ResourceHandle> _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
private UnsafeQueue<ResourceHandle> _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
@@ -60,10 +63,8 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public D3D12ResourceAllocator(D3D12RenderDevice device, RenderSystem renderSystem)
|
public D3D12ResourceAllocator(RenderSystem renderSystem, D3D12RenderDevice device, D3D12DescriptorAllocator descriptorAllocator)
|
||||||
{
|
{
|
||||||
_renderSystem = renderSystem;
|
|
||||||
|
|
||||||
var desc = new AllocatorDesc
|
var desc = new AllocatorDesc
|
||||||
{
|
{
|
||||||
pAdapter = (IDXGIAdapter*)device.Adapter,
|
pAdapter = (IDXGIAdapter*)device.Adapter,
|
||||||
@@ -72,6 +73,10 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
};
|
};
|
||||||
|
|
||||||
CreateAllocator(in desc, out _allocator);
|
CreateAllocator(in desc, out _allocator);
|
||||||
|
|
||||||
|
_device = device.NativeDevice;
|
||||||
|
_renderSystem = renderSystem;
|
||||||
|
_descriptorAllocator = descriptorAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -173,13 +178,55 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
Allocation allocation = default;
|
Allocation allocation = default;
|
||||||
ThrowIfFailed(_allocator.CreateResource(&allocationDesc, in resourceDescription, initialState, null, &allocation, IID_NULL, null));
|
ThrowIfFailed(_allocator.CreateResource(&allocationDesc, in resourceDescription, initialState, null, &allocation, IID_NULL, null));
|
||||||
|
|
||||||
return new(TrackResource(in allocation, tempResource));
|
var handle = TrackResource(in allocation, tempResource);
|
||||||
|
|
||||||
|
if (desc.Usage.HasFlag(BufferUsage.ShaderResource) && desc.CreationFlags.HasFlag(BufferCreationFlags.Bindless))
|
||||||
|
{
|
||||||
|
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
|
||||||
|
|
||||||
|
var descriptorHandle = _descriptorAllocator.AllocateBindless();
|
||||||
|
|
||||||
|
var srvDesc = new ShaderResourceViewDescription
|
||||||
|
{
|
||||||
|
ViewDimension = SrvDimension.Buffer,
|
||||||
|
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isRaw)
|
||||||
|
{
|
||||||
|
srvDesc.Format = Format.R32Typeless;
|
||||||
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
|
srvDesc.Buffer.NumElements = (uint)(desc.Size / 4);
|
||||||
|
srvDesc.Buffer.StructureByteStride = 0;
|
||||||
|
srvDesc.Buffer.Flags = BufferSrvFlags.Raw;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srvDesc.Format = Format.Unknown;
|
||||||
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
|
srvDesc.Buffer.NumElements = (uint)(desc.Size / desc.Stride);
|
||||||
|
srvDesc.Buffer.StructureByteStride = desc.Stride;
|
||||||
|
srvDesc.Buffer.Flags = BufferSrvFlags.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
_device->CreateShaderResourceView(allocation.Resource, &srvDesc, _descriptorAllocator.GetCpuHandle(descriptorHandle));
|
||||||
|
|
||||||
|
return new(handle, descriptorHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public BufferHandle CreateUploadBuffer(uint sizeInBytes, bool tempResource = false)
|
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);
|
return CreateBufferHandle(in desc, tempResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
|
|
||||||
internal unsafe static class D3D12ShaderCompiler
|
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 struct CompileResult : IDisposable
|
||||||
{
|
{
|
||||||
public UnsafeArray<byte> bytecode;
|
public UnsafeArray<byte> 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<IDxcCompiler3> compiler = default;
|
using ComPtr<IDxcCompiler3> compiler = default;
|
||||||
using ComPtr<IDxcUtils> utils = default;
|
using ComPtr<IDxcUtils> utils = default;
|
||||||
@@ -43,12 +85,12 @@ internal unsafe static class D3D12ShaderCompiler
|
|||||||
// Prepare compilation arguments - NOTE: NO -Qstrip_reflect to keep reflection data
|
// Prepare compilation arguments - NOTE: NO -Qstrip_reflect to keep reflection data
|
||||||
var argsArray = new string[]
|
var argsArray = new string[]
|
||||||
{
|
{
|
||||||
"-T", profile, // Target profile (vs_6_6, ps_6_6)
|
"-T", GetProfileString(stage, version), // Target profile (vs_6_6, ps_6_6)
|
||||||
"-E", entryPoint, // Entry point
|
"-E", GetEntryPoint(stage), // Entry point
|
||||||
"-HV", "2021", // HLSL version 2021 (required for SM 6.6)
|
"-HV", "2021", // HLSL version 2021 (required for SM 6.6)
|
||||||
"-enable-16bit-types", // Enable 16-bit types
|
"-enable-16bit-types", // Enable 16-bit types
|
||||||
"-O3", // Optimization level
|
"-O3", // Optimization level
|
||||||
"-Qstrip_debug" // Strip debug info but KEEP reflection
|
"-Qstrip_debug" // Strip debug info but KEEP reflection
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert to wide strings (DXC expects LPCWSTR)
|
// Convert to wide strings (DXC expects LPCWSTR)
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
using Win32.Graphics.Direct3D12;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of render target view (RTV) descriptor.
|
|
||||||
/// </summary>
|
|
||||||
public readonly struct RenderTargetDescriptor
|
|
||||||
{
|
|
||||||
public uint Index
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CpuDescriptorHandle CpuHandle
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RenderTargetDescriptor(uint index, CpuDescriptorHandle cpuHandle)
|
|
||||||
{
|
|
||||||
Index = index;
|
|
||||||
CpuHandle = cpuHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of depth stencil view (DSV) descriptor.
|
|
||||||
/// </summary>
|
|
||||||
public readonly struct DepthStencilDescriptor
|
|
||||||
{
|
|
||||||
public uint Index
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CpuDescriptorHandle CpuHandle
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DepthStencilDescriptor(uint index, CpuDescriptorHandle cpuHandle)
|
|
||||||
{
|
|
||||||
Index = index;
|
|
||||||
CpuHandle = cpuHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of shader resource view (SRV) descriptor.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of sampler descriptor.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of bindless descriptor for SM 6.6 rendering.
|
|
||||||
/// This descriptor maintains a 1:1 relationship between allocation indices and shader indices.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -64,7 +64,7 @@ internal unsafe class Renderer
|
|||||||
commandAllocator.Dispose();
|
commandAllocator.Dispose();
|
||||||
commandList.Dispose();
|
commandList.Dispose();
|
||||||
backBuffer.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)
|
if (frameResource.backBuffer.Get() is not null)
|
||||||
{
|
{
|
||||||
var c = frameResource.backBuffer.Reset();
|
var c = frameResource.backBuffer.Reset();
|
||||||
GraphicsPipeline.DescriptorAllocator.ReleaseRTV(frameResource.rtvDescriptor);
|
GraphicsPipeline.DescriptorAllocator.Release(frameResource.rtvDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameResource.fenceValue = _frameResources[_backBufferIndex].fenceValue;
|
frameResource.fenceValue = _frameResources[_backBufferIndex].fenceValue;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Ghost.Graphics.D3D12.Utilities;
|
|||||||
/// Specialized descriptor heap allocator for SM 6.6 bindless rendering with ResourceDescriptorHeap[index].
|
/// 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.
|
/// This allocator maintains a 1:1 relationship between allocation indices and shader indices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
internal unsafe struct BindlessDescriptorHeap : IDisposable
|
||||||
{
|
{
|
||||||
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
|
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
|
|
||||||
public readonly ConstPtr<ID3D12DescriptorHeap> BindlessHeap => new(_bindlessHeap.Get());
|
public readonly ConstPtr<ID3D12DescriptorHeap> BindlessHeap => new(_bindlessHeap.Get());
|
||||||
|
|
||||||
public BindlessDescriptorHeapAllocator(ComPtr<ID3D12Device14> device, uint numDescriptors = 10000)
|
public BindlessDescriptorHeap(ComPtr<ID3D12Device14> device, uint numDescriptors = 10000)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
device.Get()->AddRef();
|
device.Get()->AddRef();
|
||||||
@@ -67,7 +67,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
// Try to grow the heap
|
// Try to grow the heap
|
||||||
if (!Grow(NumDescriptors * 2))
|
if (!Grow(NumDescriptors * 2))
|
||||||
{
|
{
|
||||||
Debug.WriteLine("ERROR: Failed to grow bindless descriptor heap!");
|
|
||||||
return _INVALID_DESCRIPTOR_INDEX;
|
return _INVALID_DESCRIPTOR_INDEX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +87,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
var newSize = Math.Max(NumDescriptors * 2, NumDescriptors + count);
|
var newSize = Math.Max(NumDescriptors * 2, NumDescriptors + count);
|
||||||
if (!Grow(newSize))
|
if (!Grow(newSize))
|
||||||
{
|
{
|
||||||
Debug.WriteLine("ERROR: Failed to grow bindless descriptor heap!");
|
|
||||||
return _INVALID_DESCRIPTOR_INDEX;
|
return _INVALID_DESCRIPTOR_INDEX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +108,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
{
|
{
|
||||||
if (index >= NumDescriptors)
|
if (index >= NumDescriptors)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Error: Attempted to release an invalid descriptor index");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +125,6 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
var index = baseIndex + i;
|
var index = baseIndex + i;
|
||||||
if (index >= NumDescriptors)
|
if (index >= NumDescriptors)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Error: Attempted to release an invalid descriptor index");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,19 +135,19 @@ internal unsafe struct BindlessDescriptorHeapAllocator : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
|
public readonly CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
|
||||||
{
|
{
|
||||||
var handle = _startCpuHandle;
|
var handle = _startCpuHandle;
|
||||||
return handle.Offset((int)index, _stride);
|
return handle.Offset((int)index, _stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
|
public readonly GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
|
||||||
{
|
{
|
||||||
var handle = _startGpuHandle;
|
var handle = _startGpuHandle;
|
||||||
return handle.Offset((int)index, _stride);
|
return handle.Offset((int)index, _stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpuDescriptorHandle GetGpuHandleStart()
|
public readonly GpuDescriptorHandle GetGpuHandleStart()
|
||||||
{
|
{
|
||||||
return _startGpuHandle;
|
return _startGpuHandle;
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,11 @@ using DescriptorIndex = System.UInt32;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.D3D12.Utilities;
|
namespace Ghost.Graphics.D3D12.Utilities;
|
||||||
|
|
||||||
internal unsafe struct DescriptorHeapAllocator : IDisposable
|
internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||||
{
|
{
|
||||||
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
|
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
|
||||||
|
|
||||||
private ComPtr<ID3D12Device14> _device;
|
private readonly ID3D12Device14* _pDevice;
|
||||||
|
|
||||||
private ComPtr<ID3D12DescriptorHeap> _heap;
|
private ComPtr<ID3D12DescriptorHeap> _heap;
|
||||||
private ComPtr<ID3D12DescriptorHeap> _shaderVisibleHeap;
|
private ComPtr<ID3D12DescriptorHeap> _shaderVisibleHeap;
|
||||||
@@ -50,15 +50,14 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
|
|||||||
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
|
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
|
||||||
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
|
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
|
||||||
|
|
||||||
public DescriptorHeapAllocator(string name, ComPtr<ID3D12Device14> device, DescriptorHeapType type, uint numDescriptors)
|
public D3D12DescriptorHeap(string name, ID3D12Device14* device, DescriptorHeapType type, uint numDescriptors)
|
||||||
{
|
{
|
||||||
_device = device;
|
_pDevice = device;
|
||||||
device.Get()->AddRef();
|
|
||||||
|
|
||||||
HeapType = type;
|
HeapType = type;
|
||||||
NumDescriptors = numDescriptors;
|
NumDescriptors = numDescriptors;
|
||||||
ShaderVisible = type == DescriptorHeapType.CbvSrvUav || type == DescriptorHeapType.Sampler;
|
ShaderVisible = type == DescriptorHeapType.CbvSrvUav || type == DescriptorHeapType.Sampler;
|
||||||
Stride = device.Get()->GetDescriptorHandleIncrementSize(type);
|
Stride = device->GetDescriptorHandleIncrementSize(type);
|
||||||
|
|
||||||
var success = AllocateResources(numDescriptors);
|
var success = AllocateResources(numDescriptors);
|
||||||
Debug.Assert(success);
|
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;
|
var handle = _startCpuHandle;
|
||||||
return handle.Offset((int)index, Stride);
|
return handle.Offset((int)index, Stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CpuDescriptorHandle GetCpuHandleShaderVisible(DescriptorIndex index)
|
public readonly CpuDescriptorHandle GetCpuHandleShaderVisible(DescriptorIndex index)
|
||||||
{
|
{
|
||||||
var handle = _startCpuHandleShaderVisible;
|
var handle = _startCpuHandleShaderVisible;
|
||||||
return handle.Offset((int)index, Stride);
|
return handle.Offset((int)index, Stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
|
public readonly GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
|
||||||
{
|
{
|
||||||
var handle = _startGpuHandleShaderVisible;
|
var handle = _startGpuHandleShaderVisible;
|
||||||
return handle.Offset((int)index, Stride);
|
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)
|
private bool AllocateResources(uint numDescriptors)
|
||||||
@@ -193,7 +192,7 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
|
|||||||
|
|
||||||
fixed (void* heapPtr = &_heap)
|
fixed (void* heapPtr = &_heap)
|
||||||
{
|
{
|
||||||
var hr = _device.Get()->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
var hr = _pDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
||||||
if (hr.Failure)
|
if (hr.Failure)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -209,7 +208,7 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
|
|||||||
|
|
||||||
fixed (void* heapPtr = &_shaderVisibleHeap)
|
fixed (void* heapPtr = &_shaderVisibleHeap)
|
||||||
{
|
{
|
||||||
var hr = _device.Get()->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
var hr = _pDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
||||||
if (hr.Failure)
|
if (hr.Failure)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -235,11 +234,11 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
|
|||||||
return false;
|
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)
|
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;
|
return true;
|
||||||
@@ -248,8 +247,6 @@ internal unsafe struct DescriptorHeapAllocator : IDisposable
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_device.Dispose();
|
|
||||||
|
|
||||||
_heap.Dispose();
|
_heap.Dispose();
|
||||||
_shaderVisibleHeap.Dispose();
|
_shaderVisibleHeap.Dispose();
|
||||||
}
|
}
|
||||||
78
Ghost.Graphics/Data/Descriptors.cs
Normal file
78
Ghost.Graphics/Data/Descriptors.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using Win32.Graphics.Direct3D12;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Render target view (RTV) descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct RenderTargetDescriptor
|
||||||
|
{
|
||||||
|
public uint Index
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RenderTargetDescriptor Invalid => new() { Index = ~0u };
|
||||||
|
|
||||||
|
public bool IsValid => Index != ~0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Depth stencil view (DSV) descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct DepthStencilDescriptor
|
||||||
|
{
|
||||||
|
public uint Index
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DepthStencilDescriptor Invalid => new() { Index = ~0u };
|
||||||
|
|
||||||
|
public bool IsValid => Index != ~0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shader resource view (SRV) descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct ShaderResourceDescriptor
|
||||||
|
{
|
||||||
|
public uint Index
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderResourceDescriptor Invalid => new() { Index = ~0u };
|
||||||
|
|
||||||
|
public bool IsValid => Index != ~0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sampler descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct SamplerDescriptor
|
||||||
|
{
|
||||||
|
public uint Index
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SamplerDescriptor Invalid => new() { Index = ~0u };
|
||||||
|
|
||||||
|
public bool IsValid => Index != ~0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bindless descriptor
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct BindlessDescriptor
|
||||||
|
{
|
||||||
|
public uint Index
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BindlessDescriptor Invalid => new() { Index = ~0u };
|
||||||
|
|
||||||
|
public bool IsValid => Index != ~0u;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Graphics.D3D12;
|
using Ghost.Graphics.D3D12;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||||
@@ -9,18 +10,15 @@ using Win32.Graphics.Dxgi.Common;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialIndexCapacity = 512) : IDisposable
|
public unsafe sealed class Mesh : IDisposable
|
||||||
{
|
{
|
||||||
private UnsafeList<Vertex> _vertices = new(initialVertexCapacity, Allocator.Persistent);
|
private UnsafeList<Vertex> _vertices;
|
||||||
private UnsafeList<int> _indices = new(initialIndexCapacity, Allocator.Persistent);
|
private UnsafeList<int> _indices;
|
||||||
|
|
||||||
private Bounds _boundingBox;
|
private Bounds _boundingBox;
|
||||||
|
|
||||||
private GraphicsBuffer? _vertexBuffer;
|
private IBuffer? _vertexBuffer;
|
||||||
private GraphicsBuffer? _indexBuffer;
|
private IBuffer? _indexBuffer;
|
||||||
|
|
||||||
private BindlessDescriptor? _vertexBufferDescriptor;
|
|
||||||
private BindlessDescriptor? _indexBufferDescriptor;
|
|
||||||
|
|
||||||
public Span<Vertex> Vertices => _vertices.AsSpan();
|
public Span<Vertex> Vertices => _vertices.AsSpan();
|
||||||
public Span<int> Indices => _indices.AsSpan();
|
public Span<int> 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 VertexCount => (uint)_vertices.Count;
|
||||||
public uint IndexCount => (uint)_indices.Count;
|
public uint IndexCount => (uint)_indices.Count;
|
||||||
|
|
||||||
public uint VertexBufferDescriptorIndex => _vertexBufferDescriptor?.Index ?? throw new InvalidOperationException("Vertex buffer descriptor is not allocated.");
|
public uint VertexBufferDescriptorIndex
|
||||||
public uint IndexBufferDescriptorIndex => _indexBufferDescriptor?.Index ?? throw new InvalidOperationException("Index buffer descriptor is not allocated.");
|
{
|
||||||
|
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<Vertex> vertices, ReadOnlySpan<int> 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()
|
~Mesh()
|
||||||
{
|
{
|
||||||
@@ -302,6 +351,13 @@ public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialInde
|
|||||||
device->CreateShaderResourceView(_indexBuffer.NativeResource.Ptr, &indexSrvDesc, _indexBufferDescriptor.CpuHandle);
|
device->CreateShaderResourceView(_indexBuffer.NativeResource.Ptr, &indexSrvDesc, _indexBufferDescriptor.CpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void MarkNoLongerReadable()
|
||||||
|
{
|
||||||
|
_vertices.Dispose();
|
||||||
|
_indices.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all vertex and index data and releases associated GPU resources.
|
/// Clears all vertex and index data and releases associated GPU resources.
|
||||||
/// </summar>
|
/// </summar>
|
||||||
@@ -320,14 +376,14 @@ public unsafe sealed class Mesh(int initialVertexCapacity = 256, int initialInde
|
|||||||
_indexBuffer?.Dispose();
|
_indexBuffer?.Dispose();
|
||||||
_indexBuffer = null;
|
_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Win32.Graphics.D3D12MemoryAllocator;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
public readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
|
public readonly struct ResourceHandle : IEquatable<ResourceHandle>
|
||||||
{
|
{
|
||||||
private const int _INVALID_ID = -1;
|
private const int _INVALID_ID = -1;
|
||||||
|
|
||||||
@@ -20,17 +20,6 @@ public readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
|
|||||||
|
|
||||||
public bool IsValid => id != _INVALID_ID && generation >= 0;
|
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)
|
public bool Equals(ResourceHandle other)
|
||||||
{
|
{
|
||||||
return id == other.id && generation == other.generation;
|
return id == other.id && generation == other.generation;
|
||||||
@@ -49,21 +38,6 @@ public readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
|
|||||||
return obj is ResourceHandle handle && Equals(handle);
|
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)
|
public static bool operator ==(ResourceHandle left, ResourceHandle right)
|
||||||
{
|
{
|
||||||
return left.Equals(right);
|
return left.Equals(right);
|
||||||
@@ -75,7 +49,7 @@ public readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct TextureHandle : IEquatable<TextureHandle>, IDisposable
|
public readonly struct TextureHandle : IEquatable<TextureHandle>
|
||||||
{
|
{
|
||||||
private readonly ResourceHandle _resourceHandle;
|
private readonly ResourceHandle _resourceHandle;
|
||||||
|
|
||||||
@@ -104,11 +78,6 @@ public readonly struct TextureHandle : IEquatable<TextureHandle>, IDisposable
|
|||||||
return _resourceHandle.GetHashCode();
|
return _resourceHandle.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_resourceHandle.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(TextureHandle left, TextureHandle right)
|
public static bool operator ==(TextureHandle left, TextureHandle right)
|
||||||
{
|
{
|
||||||
return left.Equals(right);
|
return left.Equals(right);
|
||||||
@@ -120,16 +89,26 @@ public readonly struct TextureHandle : IEquatable<TextureHandle>, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct BufferHandle : IEquatable<BufferHandle>, IDisposable
|
public readonly struct BufferHandle : IEquatable<BufferHandle>
|
||||||
{
|
{
|
||||||
private readonly ResourceHandle _resourceHandle;
|
private readonly ResourceHandle _resourceHandle;
|
||||||
|
private readonly BindlessDescriptor _bindlessDescriptor;
|
||||||
|
|
||||||
|
public static BufferHandle Invalid => new(ResourceHandle.Invalid);
|
||||||
|
|
||||||
public ResourceHandle ResourceHandle => _resourceHandle;
|
public ResourceHandle ResourceHandle => _resourceHandle;
|
||||||
public static BufferHandle Invalid => new(ResourceHandle.Invalid);
|
public BindlessDescriptor BindlessDescriptor => _bindlessDescriptor;
|
||||||
|
|
||||||
internal BufferHandle(ResourceHandle resourceHandle)
|
internal BufferHandle(ResourceHandle resourceHandle)
|
||||||
{
|
{
|
||||||
_resourceHandle = resourceHandle;
|
_resourceHandle = resourceHandle;
|
||||||
|
_bindlessDescriptor = BindlessDescriptor.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal BufferHandle(ResourceHandle resourceHandle, BindlessDescriptor descriptor)
|
||||||
|
{
|
||||||
|
_resourceHandle = resourceHandle;
|
||||||
|
_bindlessDescriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValid => _resourceHandle.IsValid;
|
public bool IsValid => _resourceHandle.IsValid;
|
||||||
@@ -149,11 +128,6 @@ public readonly struct BufferHandle : IEquatable<BufferHandle>, IDisposable
|
|||||||
return _resourceHandle.GetHashCode();
|
return _resourceHandle.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_resourceHandle.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(BufferHandle left, BufferHandle right)
|
public static bool operator ==(BufferHandle left, BufferHandle right)
|
||||||
{
|
{
|
||||||
return left.Equals(right);
|
return left.Equals(right);
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ internal readonly struct CBufferInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bindless shader implementation using SM 6.6 with ResourceDescriptorHeap
|
/// A representation of a GPU shader, including its metadata about its resources.
|
||||||
/// and D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED
|
|
||||||
/// Enhanced to support both bindless and regular texture binding for hybrid materials
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
|
// TODO: Multi pass and keyword support
|
||||||
public unsafe class Shader : IDisposable
|
public unsafe class Shader : IDisposable
|
||||||
{
|
{
|
||||||
private readonly string _source;
|
private readonly string _source;
|
||||||
@@ -82,6 +82,7 @@ public unsafe class Shader : IDisposable
|
|||||||
internal List<TextureInfo> RegularTextures => _regularTextures;
|
internal List<TextureInfo> RegularTextures => _regularTextures;
|
||||||
internal Dictionary<string, int> PropertyNameToIdMap => _propertyNameToIdMap;
|
internal Dictionary<string, int> PropertyNameToIdMap => _propertyNameToIdMap;
|
||||||
|
|
||||||
|
// TODO: In real production, we should not load the shader source code directly.
|
||||||
internal Shader(string shaderCode)
|
internal Shader(string shaderCode)
|
||||||
{
|
{
|
||||||
_source = shaderCode;
|
_source = shaderCode;
|
||||||
|
|||||||
@@ -142,6 +142,6 @@ public abstract unsafe class Texture : GraphicsResource
|
|||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
GraphicsPipeline.DescriptorAllocator.ReleaseBindless(_bindlessDescriptor);
|
GraphicsPipeline.DescriptorAllocator.Release(_bindlessDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Ghost.Graphics.D3D12;
|
|
||||||
using Misaki.HighPerformance.Image;
|
using Misaki.HighPerformance.Image;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12-style command queue interface
|
/// Command queue interface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandQueue : IDisposable
|
public interface ICommandQueue : IDisposable
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ public interface ICommandQueue : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command queue types matching D3D12
|
/// Command queue types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CommandQueueType
|
public enum CommandQueueType
|
||||||
{
|
{
|
||||||
|
|||||||
64
Ghost.Graphics/RHI/IDescriptorAllocator.cs
Normal file
64
Ghost.Graphics/RHI/IDescriptorAllocator.cs
Normal file
@@ -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<RenderTargetDescriptor> descriptors);
|
||||||
|
|
||||||
|
public void Release(DepthStencilDescriptor descriptor);
|
||||||
|
|
||||||
|
public void Release(ReadOnlySpan<DepthStencilDescriptor> descriptors);
|
||||||
|
|
||||||
|
public void Release(ShaderResourceDescriptor descriptor);
|
||||||
|
|
||||||
|
public void Release(ReadOnlySpan<ShaderResourceDescriptor> descriptors);
|
||||||
|
|
||||||
|
public void Release(SamplerDescriptor descriptor);
|
||||||
|
|
||||||
|
public void Release(ReadOnlySpan<SamplerDescriptor> descriptors);
|
||||||
|
|
||||||
|
public void Release(BindlessDescriptor descriptor);
|
||||||
|
|
||||||
|
public void Release(ReadOnlySpan<BindlessDescriptor> descriptors);
|
||||||
|
}
|
||||||
@@ -165,7 +165,16 @@ public struct RenderTargetDesc
|
|||||||
usage |= TextureUsage.UnorderedAccess;
|
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;
|
get;
|
||||||
set;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -265,6 +261,12 @@ public struct BufferDesc
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint Stride
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Buffer usage flags
|
/// Buffer usage flags
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -274,6 +276,12 @@ public struct BufferDesc
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferCreationFlags CreationFlags
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Memory type for the buffer
|
/// Memory type for the buffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -282,13 +290,6 @@ public struct BufferDesc
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferDesc(ulong size, BufferUsage usage, MemoryType memoryType = MemoryType.Default)
|
|
||||||
{
|
|
||||||
Size = size;
|
|
||||||
Usage = usage;
|
|
||||||
MemoryType = memoryType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Ghost.Graphics.Data;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -8,17 +10,26 @@ public interface IResource : IDisposable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current resource state
|
/// Current resource state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ResourceState CurrentState { get; }
|
ResourceState CurrentState
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resource name for debugging
|
/// Resource name for debugging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; set; }
|
string Name
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the resource in bytes
|
/// Size of the resource in bytes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ulong Size { get; }
|
ulong Size
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -29,22 +40,34 @@ public interface ITexture : IResource
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the texture in pixels
|
/// Width of the texture in pixels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
uint Width { get; }
|
uint Width
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Height of the texture in pixels
|
/// Height of the texture in pixels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
uint Height { get; }
|
uint Height
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture format
|
/// Texture format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TextureFormat Format { get; }
|
TextureFormat Format
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of mip levels
|
/// Number of mip levels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
uint MipLevels { get; }
|
uint MipLevels
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -55,18 +78,26 @@ public interface IBuffer : IResource
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Buffer usage type
|
/// Buffer usage type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BufferUsage Usage { get; }
|
public BufferUsage Usage
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferHandle Handle
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps the buffer for CPU access
|
/// Maps the buffer for CPU access
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Pointer to mapped memory</returns>
|
/// <returns>Pointer to mapped memory</returns>
|
||||||
unsafe void* Map();
|
public unsafe void* Map();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unmaps the buffer from CPU access
|
/// Unmaps the buffer from CPU access
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Unmap();
|
public void Unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -78,7 +109,10 @@ public interface IRenderTarget : ITexture
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of render target (color or depth)
|
/// Type of render target (color or depth)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RenderTargetType Type { get; }
|
RenderTargetType Type
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -117,5 +151,15 @@ public enum BufferUsage
|
|||||||
Structured = 1 << 3,
|
Structured = 1 << 3,
|
||||||
Raw = 1 << 4,
|
Raw = 1 << 4,
|
||||||
Upload = 1 << 5,
|
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
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ public enum GraphicsAPI
|
|||||||
/// Application-level render system that orchestrates multiple renderers
|
/// Application-level render system that orchestrates multiple renderers
|
||||||
/// and handles frame synchronization
|
/// and handles frame synchronization
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class RenderSystem : IDisposable
|
internal class RenderSystem
|
||||||
{
|
{
|
||||||
private readonly struct FrameResource : IDisposable
|
private readonly struct FrameResource : IDisposable
|
||||||
{
|
{
|
||||||
@@ -34,15 +34,16 @@ internal class RenderSystem : IDisposable
|
|||||||
|
|
||||||
private const uint _FRAME_COUNT = 2;
|
private const uint _FRAME_COUNT = 2;
|
||||||
|
|
||||||
private readonly IGraphicsEngine _engine;
|
private readonly IGraphicsEngine _engine = null!;
|
||||||
private readonly FrameResource[] _frameResources;
|
private readonly FrameResource[] _frameResources = null!;
|
||||||
private readonly Thread _renderThread;
|
private readonly Thread _renderThread = null!;
|
||||||
private readonly AutoResetEvent _shutdownEvent;
|
private readonly AutoResetEvent _shutdownEvent = null!;
|
||||||
private ImmutableArray<IRenderer> _renderers;
|
private ImmutableArray<IRenderer> _renderers;
|
||||||
|
|
||||||
private uint _frameIndex;
|
private uint _frameIndex;
|
||||||
private uint _cpuFenceValue;
|
private uint _cpuFenceValue;
|
||||||
private uint _gpuFenceValue;
|
private uint _gpuFenceValue;
|
||||||
|
|
||||||
private bool _isRunning;
|
private bool _isRunning;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ internal class RenderSystem : IDisposable
|
|||||||
_ => throw new NotSupportedException($"Graphics API {api} is not supported.")
|
_ => throw new NotSupportedException($"Graphics API {api} is not supported.")
|
||||||
};
|
};
|
||||||
|
|
||||||
_renderers = new();
|
_renderers = ImmutableArray<IRenderer>.Empty;
|
||||||
_shutdownEvent = new(false);
|
_shutdownEvent = new(false);
|
||||||
|
|
||||||
// Create frame resources for synchronization
|
// Create frame resources for synchronization
|
||||||
@@ -75,15 +76,14 @@ internal class RenderSystem : IDisposable
|
|||||||
Name = "Graphics Render Thread",
|
Name = "Graphics Render Thread",
|
||||||
Priority = ThreadPriority.Normal
|
Priority = ThreadPriority.Normal
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
~RenderSystem()
|
_disposed = true;
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRenderer CreateRenderer()
|
public IRenderer CreateRenderer()
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var renderer = _engine.CreateRenderer();
|
var renderer = _engine.CreateRenderer();
|
||||||
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Add(renderer));
|
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Add(renderer));
|
||||||
return renderer;
|
return renderer;
|
||||||
@@ -91,11 +91,15 @@ internal class RenderSystem : IDisposable
|
|||||||
|
|
||||||
public void RemoveRenderer(IRenderer renderer)
|
public void RemoveRenderer(IRenderer renderer)
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Remove(renderer));
|
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Remove(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (_isRunning)
|
if (_isRunning)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -107,6 +111,8 @@ internal class RenderSystem : IDisposable
|
|||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (!_isRunning)
|
if (!_isRunning)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -123,12 +129,16 @@ internal class RenderSystem : IDisposable
|
|||||||
|
|
||||||
public bool WaitForGPUReady(int timeOut = -1)
|
public bool WaitForGPUReady(int timeOut = -1)
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
||||||
return _frameResources[eventIndex].gpuReadyEvent.WaitOne(timeOut);
|
return _frameResources[eventIndex].gpuReadyEvent.WaitOne(timeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalCPUReady()
|
public void SignalCPUReady()
|
||||||
{
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
||||||
_frameResources[eventIndex].cpuReadyEvent.Set();
|
_frameResources[eventIndex].cpuReadyEvent.Set();
|
||||||
_cpuFenceValue++;
|
_cpuFenceValue++;
|
||||||
@@ -184,7 +194,5 @@ internal class RenderSystem : IDisposable
|
|||||||
|
|
||||||
_shutdownEvent.Dispose();
|
_shutdownEvent.Dispose();
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user