feat(d3d12): unify resource mgmt & add pooling system
Refactored D3D12 resource and command management with a new D3D12Object<T> base class for unified lifetime and naming of COM objects. Introduced pooled command buffer and resource management in D3D12GraphicsEngine and ResourceManager, using frame-based return queues for safe reuse. Updated RenderSystem to use pooled command buffers and render requests, and to properly dispose of per-frame resources. Changed frame synchronization and resource release logic to use ulong fence/frame values for improved robustness. Refactored swap chain to DXGISwapChain and improved error handling and code clarity. Removed renderer management from IGraphicsEngine. Changed ResourceDesc, TextureDesc, and BufferDesc to record structs with equality and hashing for pooling. BREAKING CHANGE: Renderer management APIs removed from IGraphicsEngine. Frame and resource synchronization now use ulong instead of uint. Resource pooling and command buffer pooling are now required for correct usage.
This commit is contained in:
@@ -9,12 +9,8 @@ using static TerraFX.Aliases.DXGI_Alias;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
/// <summary>
|
||||
/// D3D12 implementation of the render device interface
|
||||
/// </summary>
|
||||
internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDevice
|
||||
{
|
||||
private UniquePtr<ID3D12Device14> _device;
|
||||
private UniquePtr<IDXGIFactory7> _dxgiFactory;
|
||||
private UniquePtr<IDXGIAdapter1> _adapter;
|
||||
|
||||
@@ -22,8 +18,6 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
private readonly D3D12CommandQueue _computeQueue;
|
||||
private readonly D3D12CommandQueue _copyQueue;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public ICommandQueue GraphicsQueue => _graphicsQueue;
|
||||
public ICommandQueue ComputeQueue => _computeQueue;
|
||||
public ICommandQueue CopyQueue => _copyQueue;
|
||||
@@ -34,14 +28,28 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
}
|
||||
|
||||
public SharedPtr<IDXGIFactory7> DXGIFactory => _dxgiFactory.Share();
|
||||
public SharedPtr<ID3D12Device14> NativeDevice => _device.Share();
|
||||
public SharedPtr<IDXGIAdapter1> Adapter => _adapter.Share();
|
||||
public SharedPtr<ID3D12CommandQueue> NativeGraphicsQueue => _graphicsQueue.NativeQueue;
|
||||
public SharedPtr<ID3D12CommandQueue> NativeComputeQueue => _computeQueue.NativeQueue;
|
||||
public SharedPtr<ID3D12CommandQueue> NativeCopyQueue => _copyQueue.NativeQueue;
|
||||
public SharedPtr<ID3D12CommandQueue1> NativeGraphicsQueue => _graphicsQueue.NativeObject;
|
||||
public SharedPtr<ID3D12CommandQueue1> NativeComputeQueue => _computeQueue.NativeObject;
|
||||
public SharedPtr<ID3D12CommandQueue1> NativeCopyQueue => _copyQueue.NativeObject;
|
||||
|
||||
public D3D12RenderDevice()
|
||||
:base(CreateDevice(out var dxgiFactory, out var adapter))
|
||||
{
|
||||
_dxgiFactory.Attach(dxgiFactory);
|
||||
_adapter.Attach(adapter);
|
||||
|
||||
_graphicsQueue = new D3D12CommandQueue(this, CommandQueueType.Graphics);
|
||||
_computeQueue = new D3D12CommandQueue(this, CommandQueueType.Compute);
|
||||
_copyQueue = new D3D12CommandQueue(this, CommandQueueType.Copy);
|
||||
|
||||
FeatureSupport = GetFeatureSupport();
|
||||
}
|
||||
|
||||
private static ID3D12Device14* CreateDevice(out IDXGIFactory7* dxgiFactory, out IDXGIAdapter1* adapter)
|
||||
{
|
||||
adapter = default;
|
||||
|
||||
IDXGIFactory7* pFactory = default;
|
||||
#if DEBUG
|
||||
ThrowIfFailed(CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory));
|
||||
@@ -49,29 +57,13 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
ThrowIfFailed(CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory));
|
||||
#endif
|
||||
|
||||
_dxgiFactory.Attach(pFactory);
|
||||
dxgiFactory = pFactory;
|
||||
|
||||
InitializeDevice();
|
||||
|
||||
_graphicsQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Graphics);
|
||||
_computeQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Compute);
|
||||
_copyQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Copy);
|
||||
|
||||
FeatureSupport = GetFeatureSupport();
|
||||
}
|
||||
|
||||
~D3D12RenderDevice()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void InitializeDevice()
|
||||
{
|
||||
ID3D12Device14* pDevice = default;
|
||||
IDXGIAdapter1* pAdapter = default;
|
||||
|
||||
for (uint adapterIndex = 0;
|
||||
_dxgiFactory.Get()->EnumAdapterByGpuPreference(adapterIndex, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(pAdapter), (void**)&pAdapter).SUCCEEDED;
|
||||
pFactory->EnumAdapterByGpuPreference(adapterIndex, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(pAdapter), (void**)&pAdapter).SUCCEEDED;
|
||||
adapterIndex++)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc = default;
|
||||
@@ -85,7 +77,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
|
||||
if (D3D12CreateDevice((IUnknown*)pAdapter, D3D_FEATURE_LEVEL_12_0, __uuidof(pDevice), (void**)&pDevice).SUCCEEDED)
|
||||
{
|
||||
_adapter.Attach(pAdapter);
|
||||
adapter = pAdapter;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -96,20 +88,21 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
if (pDevice == null)
|
||||
{
|
||||
pAdapter->Release(); // Dispose the last adapter we tried.
|
||||
pFactory->Release(); // Dispose the factory before throwing.
|
||||
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
||||
}
|
||||
|
||||
_device.Attach(pDevice);
|
||||
return pDevice;
|
||||
}
|
||||
|
||||
private FeatureSupport GetFeatureSupport()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ThrowIfDisposed();
|
||||
|
||||
var support = FeatureSupport.None;
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||
if (pNativeObject->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||
{
|
||||
if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3)
|
||||
{
|
||||
@@ -123,7 +116,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default;
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
||||
if (pNativeObject->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
||||
{
|
||||
if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -132,7 +125,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = default;
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
||||
if (pNativeObject->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
||||
{
|
||||
if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -141,7 +134,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = default;
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
||||
if (pNativeObject->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
||||
{
|
||||
if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -155,7 +148,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS21 options9 = default;
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS21, &options9, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS8)).SUCCEEDED)
|
||||
if (pNativeObject->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS21, &options9, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS8)).SUCCEEDED)
|
||||
{
|
||||
if (options9.WorkGraphsTier != D3D12_WORK_GRAPHS_TIER.D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -166,22 +159,13 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
return support;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_graphicsQueue.Dispose();
|
||||
_computeQueue.Dispose();
|
||||
_copyQueue.Dispose();
|
||||
|
||||
_device.Dispose();
|
||||
_dxgiFactory.Dispose();
|
||||
_adapter.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user