forked from Misaki/GhostEngine
Continue working on RHI
This commit is contained in:
@@ -1,88 +1,427 @@
|
||||
using Ghost.Graphics.RHI;
|
||||
using Win32;
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
/// <summary>
|
||||
/// D3D12 implementation of descriptor allocator interface
|
||||
/// D3D12 implementation of descriptor allocator that manages different types of descriptor heaps.
|
||||
/// </summary>
|
||||
internal unsafe class D3D12DescriptorAllocator : IDescriptorAllocator
|
||||
internal unsafe class D3D12DescriptorAllocator : IDisposable
|
||||
{
|
||||
private readonly DescriptorAllocator _internalAllocator;
|
||||
private readonly DescriptorHeapAllocator _rtvHeap;
|
||||
private readonly DescriptorHeapAllocator _dsvHeap;
|
||||
private readonly DescriptorHeapAllocator _srvHeap;
|
||||
private readonly DescriptorHeapAllocator _samplerHeap;
|
||||
private readonly BindlessDescriptorHeapAllocator _bindlessHeap;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public D3D12DescriptorAllocator(ComPtr<ID3D12Device14> device)
|
||||
public unsafe D3D12DescriptorAllocator(D3D12RenderDevice device, uint initialRtvCount = 256, uint initialDsvCount = 256, uint initialSrvCount = 1024, uint initialSamplerCount = 256, uint initialBindlessCount = 10000)
|
||||
{
|
||||
_internalAllocator = new DescriptorAllocator();
|
||||
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);
|
||||
}
|
||||
|
||||
public DescriptorHandle AllocateRTV()
|
||||
~D3D12DescriptorAllocator()
|
||||
{
|
||||
var rtvDescriptor = _internalAllocator.AllocateRTV();
|
||||
return new DescriptorHandle(rtvDescriptor.Index);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public DescriptorHandle[] AllocateRTVs(uint count)
|
||||
#region RTV Methods
|
||||
|
||||
public RenderTargetDescriptor AllocateRTV()
|
||||
{
|
||||
var rtvDescriptors = _internalAllocator.AllocateRTVs(count);
|
||||
return rtvDescriptors.Select(desc => new DescriptorHandle(desc.Index)).ToArray();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var index = _rtvHeap.AllocateDescriptor();
|
||||
if (index == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to allocate RTV descriptor");
|
||||
}
|
||||
|
||||
var cpuHandle = _rtvHeap.GetCpuHandle(index);
|
||||
return new RenderTargetDescriptor(index, cpuHandle);
|
||||
}
|
||||
|
||||
public DescriptorHandle AllocateDSV()
|
||||
public RenderTargetDescriptor[] AllocateRTVs(uint count)
|
||||
{
|
||||
var dsvDescriptor = _internalAllocator.AllocateDSV();
|
||||
return new DescriptorHandle(dsvDescriptor.Index);
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var baseIndex = _rtvHeap.AllocateDescriptors(count);
|
||||
if (baseIndex == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate {count} RTV descriptors");
|
||||
}
|
||||
|
||||
var descriptors = new RenderTargetDescriptor[count];
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
var index = baseIndex + i;
|
||||
var cpuHandle = _rtvHeap.GetCpuHandle(index);
|
||||
descriptors[i] = new RenderTargetDescriptor(index, cpuHandle);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public DescriptorHandle AllocateSRV()
|
||||
public void ReleaseRTV(RenderTargetDescriptor descriptor)
|
||||
{
|
||||
var srvDescriptor = _internalAllocator.AllocateSRV();
|
||||
return new DescriptorHandle(srvDescriptor.Index);
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (descriptor is RenderTargetDescriptor d3d12Descriptor)
|
||||
{
|
||||
_rtvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
||||
}
|
||||
}
|
||||
|
||||
public DescriptorHandle AllocateSampler()
|
||||
public void ReleaseRTVs(RenderTargetDescriptor[] descriptors)
|
||||
{
|
||||
var samplerDescriptor = _internalAllocator.AllocateSampler();
|
||||
return new DescriptorHandle(samplerDescriptor.Index);
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
ReleaseRTV(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public DescriptorHandle AllocateBindless()
|
||||
#endregion
|
||||
|
||||
#region DSV Methods
|
||||
|
||||
public DepthStencilDescriptor AllocateDSV()
|
||||
{
|
||||
var bindlessDescriptor = _internalAllocator.AllocateBindless();
|
||||
return new DescriptorHandle(bindlessDescriptor.Index);
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var index = _dsvHeap.AllocateDescriptor();
|
||||
if (index == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to allocate DSV descriptor");
|
||||
}
|
||||
|
||||
var cpuHandle = _dsvHeap.GetCpuHandle(index);
|
||||
return new DepthStencilDescriptor(index, cpuHandle);
|
||||
}
|
||||
|
||||
public void ReleaseRTV(DescriptorHandle handle)
|
||||
public DepthStencilDescriptor[] AllocateDSVs(uint count)
|
||||
{
|
||||
// TODO: Convert back to internal descriptor and release
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var baseIndex = _dsvHeap.AllocateDescriptors(count);
|
||||
if (baseIndex == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate {count} DSV descriptors");
|
||||
}
|
||||
|
||||
var descriptors = new DepthStencilDescriptor[count];
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
var index = baseIndex + i;
|
||||
var cpuHandle = _dsvHeap.GetCpuHandle(index);
|
||||
descriptors[i] = new DepthStencilDescriptor(index, cpuHandle);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public void ReleaseDSV(DescriptorHandle handle)
|
||||
public void ReleaseDSV(DepthStencilDescriptor descriptor)
|
||||
{
|
||||
// TODO: Convert back to internal descriptor and release
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (descriptor is DepthStencilDescriptor d3d12Descriptor)
|
||||
{
|
||||
_dsvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSRV(DescriptorHandle handle)
|
||||
public void ReleaseDSVs(DepthStencilDescriptor[] descriptors)
|
||||
{
|
||||
// TODO: Convert back to internal descriptor and release
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
ReleaseDSV(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSampler(DescriptorHandle handle)
|
||||
#endregion
|
||||
|
||||
#region SRV Methods
|
||||
|
||||
public ShaderResourceDescriptor AllocateSRV()
|
||||
{
|
||||
// TODO: Convert back to internal descriptor and release
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var index = _srvHeap.AllocateDescriptor();
|
||||
if (index == uint.MaxValue)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public void ReleaseBindless(DescriptorHandle handle)
|
||||
public ShaderResourceDescriptor[] AllocateSRVs(uint count)
|
||||
{
|
||||
// TODO: Convert back to internal descriptor and release
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var baseIndex = _srvHeap.AllocateDescriptors(count);
|
||||
if (baseIndex == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate {count} SRV descriptors");
|
||||
}
|
||||
|
||||
var descriptors = new ShaderResourceDescriptor[count];
|
||||
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);
|
||||
}
|
||||
|
||||
// Copy all descriptors to shader visible heap
|
||||
_srvHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public void ReleaseSRV(ShaderResourceDescriptor descriptor)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (descriptor is ShaderResourceDescriptor d3d12Descriptor)
|
||||
{
|
||||
_srvHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSRVs(ShaderResourceDescriptor[] descriptors)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
ReleaseSRV(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sampler Methods
|
||||
|
||||
public SamplerDescriptor AllocateSampler()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var index = _samplerHeap.AllocateDescriptor();
|
||||
if (index == uint.MaxValue)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public SamplerDescriptor[] AllocateSamplers(uint count)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var baseIndex = _samplerHeap.AllocateDescriptors(count);
|
||||
if (baseIndex == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate {count} Sampler descriptors");
|
||||
}
|
||||
|
||||
var descriptors = new SamplerDescriptor[count];
|
||||
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);
|
||||
}
|
||||
|
||||
// Copy all descriptors to shader visible heap
|
||||
_samplerHeap.CopyToShaderVisibleHeap(baseIndex, count);
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public void ReleaseSampler(SamplerDescriptor descriptor)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (descriptor is SamplerDescriptor d3d12Descriptor)
|
||||
{
|
||||
_samplerHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSamplers(SamplerDescriptor[] descriptors)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
ReleaseSampler(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Bindless Methods
|
||||
|
||||
/// <summary>
|
||||
/// Allocates a bindless descriptor for SM 6.6 rendering.
|
||||
/// The returned descriptor maintains a 1:1 relationship between allocation index and shader index.
|
||||
/// </summary>
|
||||
public BindlessDescriptor AllocateBindless()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var index = _bindlessHeap.AllocateDescriptor();
|
||||
if (index == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to allocate bindless descriptor");
|
||||
}
|
||||
|
||||
var cpuHandle = _bindlessHeap.GetCpuHandle(index);
|
||||
var gpuHandle = _bindlessHeap.GetGpuHandle(index);
|
||||
|
||||
return new BindlessDescriptor(index, cpuHandle, gpuHandle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates multiple bindless descriptors for SM 6.6 rendering.
|
||||
/// </summary>
|
||||
public BindlessDescriptor[] AllocateBindless(uint count)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var baseIndex = _bindlessHeap.AllocateDescriptors(count);
|
||||
if (baseIndex == uint.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate {count} bindless descriptors");
|
||||
}
|
||||
|
||||
var descriptors = new BindlessDescriptor[count];
|
||||
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);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases a bindless descriptor.
|
||||
/// </summary>
|
||||
public void ReleaseBindless(BindlessDescriptor descriptor)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (descriptor is BindlessDescriptor d3d12Descriptor)
|
||||
{
|
||||
_bindlessHeap.ReleaseDescriptor(d3d12Descriptor.Index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases multiple bindless descriptors.
|
||||
/// </summary>
|
||||
public void ReleaseBindless(BindlessDescriptor[] descriptors)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
ReleaseBindless(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RTV heap for binding to the command list.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap* GetRTVHeap() => _rtvHeap.Heap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DSV heap for binding to the command list.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap* GetDSVHeap() => _dsvHeap.Heap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SRV heap for binding to the command list.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap* GetSRVHeap() => _srvHeap.ShaderVisibleHeap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sampler heap for binding to the command list.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap* GetSamplerHeap() => _samplerHeap.ShaderVisibleHeap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bindless heap for SM 6.6 bindless rendering.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap* GetBindlessHeap() => _bindlessHeap.BindlessHeap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shader visible heaps that need to be bound to the command list.
|
||||
/// </summary>
|
||||
public ID3D12DescriptorHeap*[] GetShaderVisibleHeaps()
|
||||
{
|
||||
return [_srvHeap.ShaderVisibleHeap, _samplerHeap.ShaderVisibleHeap];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shader visible heaps including bindless heap for SM 6.6 rendering.
|
||||
/// </summary>
|
||||
public ConstPtr<ID3D12DescriptorHeap>[] GetShaderVisibleHeapsWithBindless()
|
||||
{
|
||||
return [_bindlessHeap.BindlessHeap, _srvHeap.ShaderVisibleHeap, _samplerHeap.ShaderVisibleHeap];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_rtvHeap.Dispose();
|
||||
_dsvHeap.Dispose();
|
||||
_srvHeap.Dispose();
|
||||
_samplerHeap.Dispose();
|
||||
_bindlessHeap.Dispose();
|
||||
|
||||
_internalAllocator?.Dispose();
|
||||
_disposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user