Refactor and enhance resource management and rendering
Updated multiple components to improve encapsulation, maintainability, and performance. Key changes include: - Upgraded package dependencies in project files. - Refactored `Mesh` and `RenderingContext` to use properties and added support for per-object constant buffers. - Improved resource management in `D3D12CommandBuffer`, `D3D12CommandQueue`, and `D3D12ResourceAllocator` with better encapsulation and disposal handling. - Added validation for constant buffer sizes in `D3D12PipelineLibrary`. - Simplified `MeshBuilder` methods to accept allocators and removed hardcoded values. - Enhanced debugging with `GPUResourceLeakException` and resource tracking updates. - Updated shaders and rendering logic for testing, including hardcoded triangle rendering. - Removed redundant base classes and interfaces for cleaner code structure.
This commit is contained in:
@@ -8,14 +8,16 @@ using Misaki.HighPerformance.LowLevel.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
using static TerraFX.Aliases.D3D_Alias;
|
||||
using static TerraFX.Aliases.D3D12_Alias;
|
||||
using static TerraFX.Aliases.DXGI_Alias;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList10>, ICommandBuffer
|
||||
internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
{
|
||||
private UniquePtr<ID3D12GraphicsCommandList10> _commandList;
|
||||
private UniquePtr<ID3D12CommandAllocator> _allocator;
|
||||
|
||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||
@@ -26,12 +28,28 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
|
||||
private ushort _commandCount;
|
||||
private bool _isRecording;
|
||||
private bool _disposed;
|
||||
|
||||
public ID3D12GraphicsCommandList10* NativeCommandList => nativeObject.Get();
|
||||
public SharedPtr<ID3D12GraphicsCommandList10> NativeCommandList => _commandList.Get();
|
||||
|
||||
public CommandBufferType Type => _type;
|
||||
public bool IsEmpty => _commandCount == 0;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => field;
|
||||
set
|
||||
{
|
||||
if (field == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
_commandList.Get()->SetName(value);
|
||||
}
|
||||
} = string.Empty;
|
||||
|
||||
public D3D12CommandBuffer(
|
||||
D3D12RenderDevice device,
|
||||
D3D12PipelineLibrary stateController,
|
||||
@@ -46,11 +64,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ID3D12GraphicsCommandList10* pCommandList = default;
|
||||
var commandListType = ConvertCommandBufferType(type);
|
||||
|
||||
device.NativeDevice->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator);
|
||||
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
|
||||
device.NativeDevice.Get()->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator);
|
||||
device.NativeDevice.Get()->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
|
||||
|
||||
_allocator.Attach(pAllocator);
|
||||
nativeObject.Attach(pCommandList);
|
||||
_commandList.Attach(pCommandList);
|
||||
|
||||
_pipelineLibrary = stateController;
|
||||
_resourceDatabase = resourceDatabase;
|
||||
@@ -60,6 +78,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
_isRecording = false;
|
||||
}
|
||||
|
||||
~D3D12CommandBuffer()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type)
|
||||
{
|
||||
return type switch
|
||||
@@ -71,6 +94,12 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ThrowIfRecording()
|
||||
{
|
||||
@@ -100,7 +129,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
void ResetCommandList()
|
||||
{
|
||||
ThrowIfFailed(_allocator.Get()->Reset());
|
||||
ThrowIfFailed(nativeObject.Get()->Reset(_allocator.Get(), null));
|
||||
ThrowIfFailed(_commandList.Get()->Reset(_allocator.Get(), null));
|
||||
}
|
||||
|
||||
void SetBindlessHeap()
|
||||
@@ -108,14 +137,18 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var heaps = stackalloc ID3D12DescriptorHeap*[2];
|
||||
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
|
||||
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
|
||||
nativeObject.Get()->SetDescriptorHeaps(2, heaps);
|
||||
_commandList.Get()->SetDescriptorHeaps(2, heaps);
|
||||
}
|
||||
|
||||
ThrowIfDisposed();
|
||||
ThrowIfRecording();
|
||||
|
||||
ResetCommandList();
|
||||
SetBindlessHeap();
|
||||
|
||||
if (Type == CommandBufferType.Graphics || Type == CommandBufferType.Compute)
|
||||
{
|
||||
SetBindlessHeap();
|
||||
}
|
||||
|
||||
_commandCount = 0;
|
||||
_isRecording = true;
|
||||
@@ -126,7 +159,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotRecording();
|
||||
|
||||
nativeObject.Get()->Close();
|
||||
_commandList.Get()->Close();
|
||||
_isRecording = false;
|
||||
}
|
||||
|
||||
@@ -137,7 +170,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
IncrementCommandCount();
|
||||
|
||||
var d3d12Rect = new RECT((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);
|
||||
nativeObject.Get()->RSSetScissorRects(1, &d3d12Rect);
|
||||
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
|
||||
}
|
||||
|
||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
|
||||
@@ -150,7 +183,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
|
||||
before.ToD3D12States(), after.ToD3D12States());
|
||||
|
||||
nativeObject.Get()->ResourceBarrier(1, &barrier);
|
||||
_commandList.Get()->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
||||
@@ -168,17 +201,17 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||
}
|
||||
|
||||
var descriptor = _resourceDatabase.GetResourceInfo(handle.AsResource()).viewGroup;
|
||||
var descriptor = _resourceDatabase.GetResourceRecord(handle.AsResource()).viewGroup;
|
||||
pRtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
|
||||
}
|
||||
|
||||
var pDsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
|
||||
if (pDsvHandle != null)
|
||||
{
|
||||
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv);
|
||||
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceRecord(depthTarget.AsResource()).viewGroup.dsv);
|
||||
}
|
||||
|
||||
nativeObject.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
|
||||
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
|
||||
}
|
||||
|
||||
public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false)
|
||||
@@ -196,7 +229,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||
}
|
||||
|
||||
var resourceInfo = _resourceDatabase.GetResourceInfo(rtDesc.Texture.AsResource());
|
||||
var resourceInfo = _resourceDatabase.GetResourceRecord(rtDesc.Texture.AsResource());
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv);
|
||||
|
||||
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
|
||||
@@ -212,6 +245,10 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
Format = resourceInfo.desc.TextureDescription.Format.ToDXGIFormat(),
|
||||
}
|
||||
}
|
||||
},
|
||||
EndingAccess = new D3D12_RENDER_PASS_ENDING_ACCESS
|
||||
{
|
||||
Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
|
||||
}
|
||||
};
|
||||
|
||||
@@ -226,7 +263,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.Texture.IsValid ? 1 : 0];
|
||||
if (pDsvDesc != null)
|
||||
{
|
||||
var resourceInfo = _resourceDatabase.GetResourceInfo(depthDesc.Texture.AsResource());
|
||||
var resourceInfo = _resourceDatabase.GetResourceRecord(depthDesc.Texture.AsResource());
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv);
|
||||
|
||||
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
|
||||
@@ -253,7 +290,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
pDsvDesc[0] = desc;
|
||||
}
|
||||
|
||||
nativeObject.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
|
||||
_commandList.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
|
||||
allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE);
|
||||
}
|
||||
|
||||
@@ -263,7 +300,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
nativeObject.Get()->EndRenderPass();
|
||||
_commandList.Get()->EndRenderPass();
|
||||
}
|
||||
|
||||
public void SetViewport(ViewportDesc viewport)
|
||||
@@ -272,8 +309,8 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var d3d12Viewport = new D3D12_VIEWPORT(viewport.Width, viewport.Height, viewport.X, viewport.Y, viewport.MinDepth, viewport.MaxDepth);
|
||||
nativeObject.Get()->RSSetViewports(1, &d3d12Viewport);
|
||||
var d3d12Viewport = new D3D12_VIEWPORT(viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth);
|
||||
_commandList.Get()->RSSetViewports(1, &d3d12Viewport);
|
||||
}
|
||||
|
||||
public void SetPipelineState(GraphicsPipelineKey pipelineKey)
|
||||
@@ -288,9 +325,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
Logger.LogError($"Failed to get graphics pipeline state object for key {pipelineKey}: {psor.Status}");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
nativeObject.Get()->SetPipelineState(psor.Value);
|
||||
|
||||
_commandList.Get()->SetGraphicsRootSignature(_pipelineLibrary.DefaultRootSignature);
|
||||
_commandList.Get()->SetPipelineState(psor.Value);
|
||||
}
|
||||
|
||||
public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer)
|
||||
@@ -300,7 +339,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
IncrementCommandCount();
|
||||
|
||||
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
nativeObject.Get()->SetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress());
|
||||
_commandList.Get()->SetGraphicsRootConstantBufferView(slot, resource.Get()->GetGPUVirtualAddress());
|
||||
}
|
||||
|
||||
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
|
||||
@@ -309,15 +348,15 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
var vbView = new D3D12_VERTEX_BUFFER_VIEW
|
||||
{
|
||||
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
|
||||
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
|
||||
BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset,
|
||||
SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset),
|
||||
StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).BufferDescription.Stride
|
||||
};
|
||||
|
||||
nativeObject.Get()->IASetVertexBuffers(slot, 1, &vbView);
|
||||
_commandList.Get()->IASetVertexBuffers(slot, 1, &vbView);
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0)
|
||||
@@ -326,15 +365,15 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
var ibView = new D3D12_INDEX_BUFFER_VIEW
|
||||
{
|
||||
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
|
||||
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
|
||||
BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset,
|
||||
SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset),
|
||||
Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT
|
||||
};
|
||||
|
||||
nativeObject.Get()->IASetIndexBuffer(&ibView);
|
||||
_commandList.Get()->IASetIndexBuffer(&ibView);
|
||||
}
|
||||
|
||||
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||
@@ -351,7 +390,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
_ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
|
||||
};
|
||||
|
||||
nativeObject.Get()->IASetPrimitiveTopology(d3d12Topology);
|
||||
_commandList.Get()->IASetPrimitiveTopology(d3d12Topology);
|
||||
}
|
||||
|
||||
public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0)
|
||||
@@ -360,7 +399,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
nativeObject.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance);
|
||||
_commandList.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance);
|
||||
}
|
||||
|
||||
public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0)
|
||||
@@ -369,7 +408,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
nativeObject.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
||||
_commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
||||
}
|
||||
|
||||
public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||
@@ -378,7 +417,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
nativeObject.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||
_commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||
}
|
||||
|
||||
public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||
@@ -387,7 +426,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
nativeObject.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||
_commandList.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||
}
|
||||
|
||||
public void DispatchRay()
|
||||
@@ -398,7 +437,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
// ThrowIfNotRecording();
|
||||
// IncrementCommandCount();
|
||||
|
||||
// nativeObject.Get()->DispatchRays();
|
||||
// _device.Get()->DispatchRays();
|
||||
}
|
||||
|
||||
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
||||
@@ -411,19 +450,19 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var sizeInBytes = (uint)(data.Length * sizeof(T));
|
||||
|
||||
var uploadHandle = _resourceAllocator.CreateUploadBuffer(sizeInBytes);
|
||||
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
|
||||
void* pMappedData;
|
||||
pUploadResource->Map(0, null, &pMappedData);
|
||||
uploadResource.Get()->Map(0, null, &pMappedData);
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
MemoryUtility.MemCpy(pMappedData, pData, sizeInBytes);
|
||||
MemoryUtility.MemCpy(pData, pMappedData, sizeInBytes);
|
||||
}
|
||||
pUploadResource->Unmap(0, null);
|
||||
uploadResource.Get()->Unmap(0, null);
|
||||
|
||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
|
||||
nativeObject.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes);
|
||||
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
|
||||
}
|
||||
|
||||
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
||||
@@ -432,10 +471,10 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var pResource = _resourceDatabase.GetResource(texture.AsResource());
|
||||
var resource = _resourceDatabase.GetResource(texture.AsResource());
|
||||
|
||||
var resourceDesc = pResource->GetDesc();
|
||||
var requiredSize = GetRequiredIntermediateSize(pResource, 0, (uint)subresources.Length);
|
||||
var resourceDesc = resource.Get()->GetDesc();
|
||||
var requiredSize = GetRequiredIntermediateSize(resource, 0, (uint)subresources.Length);
|
||||
|
||||
var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize);
|
||||
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
@@ -452,8 +491,8 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
}
|
||||
|
||||
UpdateSubresources(
|
||||
(ID3D12GraphicsCommandList*)nativeObject.Get(),
|
||||
pResource,
|
||||
(ID3D12GraphicsCommandList*)_commandList.Get(),
|
||||
resource,
|
||||
pUploadResource,
|
||||
0,
|
||||
0,
|
||||
@@ -476,17 +515,17 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
|
||||
if (numBytes == 0)
|
||||
{
|
||||
nativeObject.Get()->CopyResource(pDestResource, pSrcResource);
|
||||
_commandList.Get()->CopyResource(pDestResource, pSrcResource);
|
||||
}
|
||||
else
|
||||
{
|
||||
nativeObject.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes);
|
||||
_commandList.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -496,9 +535,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
throw new InvalidOperationException("Command buffer is still recording");
|
||||
}
|
||||
|
||||
_commandList.Dispose();
|
||||
_allocator.Dispose();
|
||||
_commandCount = 0;
|
||||
|
||||
base.Dispose(disposing);
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using TerraFX.Interop.DirectX;
|
||||
@@ -10,18 +9,21 @@ namespace Ghost.Graphics.D3D12;
|
||||
/// <summary>
|
||||
/// D3D12 implementation of command queue interface
|
||||
/// </summary>
|
||||
internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, ICommandQueue
|
||||
internal unsafe class D3D12CommandQueue : ICommandQueue
|
||||
{
|
||||
private UniquePtr<ID3D12CommandQueue> _commandQueue;
|
||||
private UniquePtr<ID3D12Fence1> _fence;
|
||||
|
||||
private readonly AutoResetEvent _fenceEvent;
|
||||
private ulong _fenceValue;
|
||||
private bool _disposed;
|
||||
|
||||
public CommandQueueType Type
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ID3D12CommandQueue* NativeQueue => nativeObject.Get();
|
||||
public SharedPtr<ID3D12CommandQueue> NativeQueue => _commandQueue.Get();
|
||||
|
||||
public D3D12CommandQueue(ID3D12Device14* pDevice, CommandQueueType type)
|
||||
{
|
||||
@@ -41,10 +43,15 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
ThrowIfFailed(pDevice->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue));
|
||||
ThrowIfFailed(pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence));
|
||||
|
||||
nativeObject.Attach(pQueue);
|
||||
_commandQueue.Attach(pQueue);
|
||||
_fence.Attach(pFence);
|
||||
}
|
||||
|
||||
~D3D12CommandQueue()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private static D3D12_COMMAND_LIST_TYPE ConvertCommandQueueType(CommandQueueType type)
|
||||
{
|
||||
return type switch
|
||||
@@ -58,7 +65,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
|
||||
public void Submit(ICommandBuffer commandBuffer)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (commandBuffer.IsEmpty)
|
||||
{
|
||||
@@ -68,8 +75,8 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
if (commandBuffer is D3D12CommandBuffer d3d12CommandBuffer)
|
||||
{
|
||||
var commandList = d3d12CommandBuffer.NativeCommandList;
|
||||
var commandListPtr = (ID3D12CommandList*)commandList;
|
||||
nativeObject.Get()->ExecuteCommandLists(1, &commandListPtr);
|
||||
var commandListPtr = (ID3D12CommandList*)commandList.Get();
|
||||
_commandQueue.Get()->ExecuteCommandLists(1, &commandListPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -79,7 +86,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
|
||||
public void Submit(params ReadOnlySpan<ICommandBuffer> commandBuffers)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
Span<int> executableIndices = stackalloc int[commandBuffers.Length];
|
||||
executableIndices.Fill(-1);
|
||||
@@ -107,7 +114,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
|
||||
if (commandBuffers[cmdIndex] is D3D12CommandBuffer d3d12CommandBuffer)
|
||||
{
|
||||
ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList;
|
||||
ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,21 +124,21 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
nativeObject.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists);
|
||||
_commandQueue.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists);
|
||||
}
|
||||
|
||||
public ulong Signal(ulong value)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
_fenceValue = value;
|
||||
nativeObject.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue);
|
||||
_commandQueue.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue);
|
||||
return _fenceValue;
|
||||
}
|
||||
|
||||
public void WaitForValue(ulong value)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (_fence.Get()->GetCompletedValue() < value)
|
||||
{
|
||||
@@ -145,28 +152,30 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
||||
|
||||
public ulong GetCompletedValue()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
return _fence.Get()->GetCompletedValue();
|
||||
}
|
||||
|
||||
public void WaitIdle()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var fenceValue = Signal(Interlocked.Increment(ref _fenceValue));
|
||||
WaitForValue(fenceValue);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_fenceEvent?.Dispose();
|
||||
_commandQueue.Dispose();
|
||||
_fence.Dispose();
|
||||
_fenceEvent?.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
public ISwapChain CreateSwapChain(SwapChainDesc desc)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return new D3D12SwapChain(_resourceDatabase, _device.DXGIFactory, ((D3D12CommandQueue)_device.GraphicsQueue).NativeQueue, desc);
|
||||
return new D3D12SwapChain(_resourceDatabase, _descriptorAllocator, _device, desc);
|
||||
}
|
||||
|
||||
public void BeginFrame()
|
||||
@@ -152,6 +152,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
_resourceDatabase.Dispose();
|
||||
|
||||
_descriptorAllocator.Dispose();
|
||||
_shaderCompiler.Dispose();
|
||||
_device.Dispose();
|
||||
#if DEBUG
|
||||
_debugLayer.Dispose();
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal abstract class D3D12RHIObject : IRHIObject
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get; set;
|
||||
} = string.Empty;
|
||||
}
|
||||
|
||||
internal abstract unsafe class D3D12Object<T> : IRHIObject, IDisposable
|
||||
where T : unmanaged, ID3D12Object.Interface
|
||||
{
|
||||
private bool _disposed;
|
||||
private string _name = string.Empty;
|
||||
|
||||
protected UniquePtr<T> nativeObject;
|
||||
|
||||
protected bool Disposed => _disposed;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_name = value;
|
||||
if (nativeObject.Get() != null)
|
||||
{
|
||||
nativeObject.Get()->SetName(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~D3D12Object()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nativeObject.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal abstract class IUnknownObject<T> : IRHIObject, IDisposable
|
||||
where T : unmanaged, IUnknown.Interface
|
||||
{
|
||||
private bool _disposed;
|
||||
private string _name = string.Empty;
|
||||
|
||||
protected UniquePtr<T> nativeObject;
|
||||
|
||||
protected bool Disposed => _disposed;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
~IUnknownObject()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nativeObject.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ internal struct D3D12PipelineState : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
{
|
||||
private readonly D3D12RenderDevice _device;
|
||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||
@@ -153,7 +153,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
}
|
||||
|
||||
ID3D12RootSignature* pRootSignature = default;
|
||||
ThrowIfFailed(_device.NativeDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
|
||||
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||
|
||||
_defaultRootSignature.Attach(pRootSignature);
|
||||
@@ -183,12 +183,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
var fileBytes = File.ReadAllBytes(filePath!);
|
||||
fixed (byte* pFileBytes = fileBytes)
|
||||
{
|
||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary));
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary));
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary));
|
||||
}
|
||||
|
||||
_library.Attach(pLibrary);
|
||||
@@ -213,18 +213,26 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
|
||||
private static Result<CBufferInfo> ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||
{
|
||||
CBufferInfo cbufferInfo;
|
||||
var cbufferInfo = default(CBufferInfo);
|
||||
|
||||
foreach (var info in reflectionData.ResourcesBindings)
|
||||
{
|
||||
if (info.BindPoint > 3)
|
||||
if (info.BindPoint >= RootSignatureLayout.ROOT_PARAMETER_COUNT)
|
||||
{
|
||||
return Result.Failure($"Resource binding point {info.BindPoint} is out of range. Only binding points 0-3 are supported in the current root signature.");
|
||||
}
|
||||
|
||||
if (info.Type != ShaderInputType.ConstantBuffer)
|
||||
{
|
||||
return Result.Failure($"Resource binding type {info.Type} is not supported. Only constant buffers are supported in the current root signature.");
|
||||
return Result.Failure($"Resource binding type {info.Type} is not supported. Please consider using bindless resources for buffers, textures and samplers.");
|
||||
}
|
||||
|
||||
if (info.BindPoint == RootSignatureLayout.PER_OBJECT_BUFFER_SLOT)
|
||||
{
|
||||
if (info.Size != sizeof(PerObjectData))
|
||||
{
|
||||
return Result.Failure($"Per-object constant buffer size mismatch. Expected size: {sizeof(PerObjectData)}, Actual size: {info.Size}");
|
||||
}
|
||||
}
|
||||
|
||||
if (info.BindPoint == RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT)
|
||||
@@ -237,19 +245,15 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
SizeInBytes = info.Size,
|
||||
Properties = info.Properties ?? Array.Empty<CBufferPropertyInfo>(),
|
||||
};
|
||||
|
||||
return Result.Success(cbufferInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Failure("Per-material constant buffer not found in shader reflection data.");
|
||||
|
||||
// TODO: Validate Cbuffer sizes and bindings.
|
||||
return Result.Success(cbufferInfo);
|
||||
}
|
||||
|
||||
private static D3D12_COMPARISON_FUNC ToD3DCompare(ZTestOptions z) => z switch
|
||||
{
|
||||
ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_ALWAYS,
|
||||
ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_NEVER,
|
||||
ZTestOptions.Less => D3D12_COMPARISON_FUNC_LESS,
|
||||
ZTestOptions.LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
||||
ZTestOptions.Equal => D3D12_COMPARISON_FUNC_EQUAL,
|
||||
@@ -284,7 +288,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message);
|
||||
}
|
||||
|
||||
if (msr.Value != psr.Value)
|
||||
if (msr.Value.Properties != null
|
||||
&& msr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||
{
|
||||
return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match.");
|
||||
}
|
||||
@@ -297,12 +302,14 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message);
|
||||
}
|
||||
|
||||
if (tsr.Value != msr.Value)
|
||||
if (tsr.Value.Properties != null
|
||||
&& tsr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||
{
|
||||
return Result.Failure("Task shader and mesh shader constant buffer layouts do not match.");
|
||||
return Result.Failure("Task shader and pixel shader constant buffer layouts do not match.");
|
||||
}
|
||||
}
|
||||
|
||||
// ts and ms may not use per material cbuffer at all, so we return the psr value.
|
||||
return psr.Value;
|
||||
}
|
||||
|
||||
@@ -396,7 +403,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
if (hr == E.E_INVALIDARG)
|
||||
{
|
||||
// Pipeline not found in the library, create a new one.
|
||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||
ThrowIfFailed(_library.Get()->StorePipeline(pKeyStr, pPipelineState));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -12,8 +12,9 @@ namespace Ghost.Graphics.D3D12;
|
||||
/// <summary>
|
||||
/// D3D12 implementation of the render device interface
|
||||
/// </summary>
|
||||
internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDevice
|
||||
internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||
{
|
||||
private UniquePtr<ID3D12Device14> _device;
|
||||
private UniquePtr<IDXGIFactory7> _dxgiFactory;
|
||||
private UniquePtr<IDXGIAdapter1> _adapter;
|
||||
|
||||
@@ -21,21 +22,35 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
private readonly D3D12CommandQueue _computeQueue;
|
||||
private readonly D3D12CommandQueue _copyQueue;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public ICommandQueue GraphicsQueue => _graphicsQueue;
|
||||
public ICommandQueue ComputeQueue => _computeQueue;
|
||||
public ICommandQueue CopyQueue => _copyQueue;
|
||||
|
||||
public IDXGIFactory7* DXGIFactory => _dxgiFactory.Get();
|
||||
public ID3D12Device14* NativeDevice => nativeObject.Get();
|
||||
public IDXGIAdapter1* Adapter => _adapter.Get();
|
||||
public SharedPtr<IDXGIFactory7> DXGIFactory => _dxgiFactory.Get();
|
||||
public SharedPtr<ID3D12Device14> NativeDevice => _device.Get();
|
||||
public SharedPtr<IDXGIAdapter1> Adapter => _adapter.Get();
|
||||
public SharedPtr<ID3D12CommandQueue> NativeGraphicsQueue => _graphicsQueue.NativeQueue;
|
||||
public SharedPtr<ID3D12CommandQueue> NativeComputeQueue => _computeQueue.NativeQueue;
|
||||
public SharedPtr<ID3D12CommandQueue> NativeCopyQueue => _copyQueue.NativeQueue;
|
||||
|
||||
public D3D12RenderDevice()
|
||||
{
|
||||
IDXGIFactory7* pFactory = default;
|
||||
#if DEBUG
|
||||
ThrowIfFailed(CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory));
|
||||
#else
|
||||
ThrowIfFailed(CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory));
|
||||
#endif
|
||||
|
||||
_dxgiFactory.Attach(pFactory);
|
||||
|
||||
InitializeDevice();
|
||||
|
||||
_graphicsQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Graphics);
|
||||
_computeQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Compute);
|
||||
_copyQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Copy);
|
||||
_graphicsQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Graphics);
|
||||
_computeQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Compute);
|
||||
_copyQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Copy);
|
||||
}
|
||||
|
||||
~D3D12RenderDevice()
|
||||
@@ -45,15 +60,6 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
|
||||
private void InitializeDevice()
|
||||
{
|
||||
IDXGIFactory7* pFactory = default;
|
||||
#if DEBUG
|
||||
CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory);
|
||||
#else
|
||||
CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory);
|
||||
#endif
|
||||
|
||||
_dxgiFactory.Attach(pFactory);
|
||||
|
||||
ID3D12Device14* pDevice = default;
|
||||
IDXGIAdapter1* pAdapter = default;
|
||||
|
||||
@@ -86,17 +92,17 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
||||
}
|
||||
|
||||
nativeObject.Attach(pDevice);
|
||||
_device.Attach(pDevice);
|
||||
}
|
||||
|
||||
public FeatureSupport GetFeatureSupport()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
FeatureSupport support = FeatureSupport.None;
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||
{
|
||||
if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3)
|
||||
{
|
||||
@@ -105,7 +111,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default;
|
||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
||||
{
|
||||
if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -114,7 +120,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = default;
|
||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
||||
{
|
||||
if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -123,7 +129,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = default;
|
||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
||||
{
|
||||
if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED)
|
||||
{
|
||||
@@ -139,9 +145,9 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
return support;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -150,9 +156,11 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
||||
_computeQueue.Dispose();
|
||||
_copyQueue.Dispose();
|
||||
|
||||
_device.Dispose();
|
||||
_dxgiFactory.Dispose();
|
||||
_adapter.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,17 @@ namespace Ghost.Graphics.D3D12;
|
||||
/// <summary>
|
||||
/// D3D12 implementation of the renderer interface using RHI abstractions
|
||||
/// </summary>
|
||||
internal unsafe class D3D12Renderer : IRenderer
|
||||
internal class D3D12Renderer : IRenderer
|
||||
{
|
||||
private struct FrameResource : IDisposable
|
||||
{
|
||||
public ICommandBuffer commandBuffer;
|
||||
public ulong fenceValue;
|
||||
|
||||
public FrameResource(D3D12GraphicsEngine graphicsEngine)
|
||||
public FrameResource(D3D12GraphicsEngine graphicsEngine, int index)
|
||||
{
|
||||
commandBuffer = graphicsEngine.CreateCommandBuffer();
|
||||
commandBuffer.Name = $"Frame Command Buffer {index}";
|
||||
fenceValue = 0;
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
_frameResources = new FrameResource[D3D12PipelineResource.BACK_BUFFER_COUNT];
|
||||
for (var i = 0; i < _frameResources.Length; i++)
|
||||
{
|
||||
_frameResources[i] = new FrameResource(graphicsEngine);
|
||||
_frameResources[i] = new FrameResource(graphicsEngine, i);
|
||||
}
|
||||
|
||||
_renderTarget = Handle<Texture>.Invalid;
|
||||
@@ -108,6 +109,12 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
CreateOffScreenRenderTarget(swapChain.Width, swapChain.Height);
|
||||
}
|
||||
|
||||
var newSize = swapChain != null ? new uint2(swapChain.Width, swapChain.Height) : _currentSize;
|
||||
if (!math.all(newSize == _currentSize))
|
||||
{
|
||||
RequestResize(newSize);
|
||||
}
|
||||
|
||||
_swapChain = swapChain;
|
||||
}
|
||||
|
||||
@@ -171,9 +178,22 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
frame.commandBuffer.Begin();
|
||||
|
||||
// NOTE: Temperary solution: render directly to the swap chain back buffer if available.
|
||||
// HACK: This is hard coded for testing purposes only.
|
||||
|
||||
var rt = _swapChain?.GetCurrentBackBuffer() ?? _renderTarget;
|
||||
|
||||
if(_swapChain != null)
|
||||
{
|
||||
frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
|
||||
}
|
||||
|
||||
RenderScene(rt, frame.commandBuffer);
|
||||
|
||||
if (_swapChain != null)
|
||||
{
|
||||
frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.RenderTarget, ResourceState.Present);
|
||||
}
|
||||
|
||||
// if (_swapChain != null)
|
||||
// {
|
||||
// var backBufferRT = _swapChain.GetCurrentBackBuffer();
|
||||
@@ -196,12 +216,14 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
{
|
||||
var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f };
|
||||
|
||||
Span<PassRenderTargetDesc> rtDesc = stackalloc PassRenderTargetDesc[1];
|
||||
rtDesc[0] = new PassRenderTargetDesc
|
||||
{
|
||||
Texture = target,
|
||||
ClearColor = clearColor,
|
||||
};
|
||||
Span<PassRenderTargetDesc> rtDesc =
|
||||
[
|
||||
new PassRenderTargetDesc
|
||||
{
|
||||
Texture = target,
|
||||
ClearColor = clearColor,
|
||||
},
|
||||
];
|
||||
|
||||
var depthDesc = new PassDepthStencilDesc
|
||||
{
|
||||
@@ -217,11 +239,10 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
_pass.Initialize(ref ctx);
|
||||
}
|
||||
|
||||
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
||||
|
||||
var viewport = new ViewportDesc { Width = _currentSize.x, Height = _currentSize.y, MinDepth = 0, MaxDepth = 1 };
|
||||
var scissor = new RectDesc { Right = _currentSize.x, Bottom = _currentSize.y };
|
||||
|
||||
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
||||
cmd.SetViewport(viewport);
|
||||
cmd.SetScissorRect(scissor);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Ghost.Core.Graphics;
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -132,13 +133,13 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
var resourceDesc = pResource->GetDesc();
|
||||
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
|
||||
{
|
||||
Format = resourceDesc.Format,
|
||||
ViewDimension = D3D12_SRV_DIMENSION_BUFFER,
|
||||
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
|
||||
};
|
||||
|
||||
if (isRaw)
|
||||
{
|
||||
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
srvDesc.Buffer.FirstElement = 0;
|
||||
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
||||
srvDesc.Buffer.StructureByteStride = 0;
|
||||
@@ -146,6 +147,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
}
|
||||
else // Assumes Structured
|
||||
{
|
||||
srvDesc.Format = resourceDesc.Format;
|
||||
srvDesc.Buffer.FirstElement = 0;
|
||||
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
||||
srvDesc.Buffer.StructureByteStride = stride;
|
||||
@@ -406,12 +408,12 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
var resourceDesc = pResource->GetDesc();
|
||||
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
|
||||
{
|
||||
Format = resourceDesc.Format,
|
||||
ViewDimension = D3D12_UAV_DIMENSION_BUFFER,
|
||||
};
|
||||
|
||||
if (isRaw)
|
||||
{
|
||||
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
uavDesc.Buffer.FirstElement = 0;
|
||||
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
||||
uavDesc.Buffer.StructureByteStride = 0;
|
||||
@@ -419,6 +421,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
}
|
||||
else // Assumes Structured
|
||||
{
|
||||
uavDesc.Format = resourceDesc.Format;
|
||||
uavDesc.Buffer.FirstElement = 0;
|
||||
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
||||
uavDesc.Buffer.StructureByteStride = stride;
|
||||
@@ -521,6 +524,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
|
||||
// Default to Common, but check for specific roles
|
||||
var state = D3D12_RESOURCE_STATE_COMMON;
|
||||
return state;
|
||||
|
||||
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
|
||||
{
|
||||
@@ -591,8 +595,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
// TODO: Thread safety for resource allocator
|
||||
// A common solution is to use ticket. Each pAllocation request create a ticket and put it into a thread-safe queue. A dedicated thread process the queue and fulfill the requests.
|
||||
|
||||
internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D12MA_Allocator>, IResourceAllocator
|
||||
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
{
|
||||
private UniquePtr<D3D12MA_Allocator> _d3d12MA;
|
||||
|
||||
private readonly IFenceSynchronizer _fenceSynchronizer;
|
||||
private readonly D3D12RenderDevice _device;
|
||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||
@@ -601,6 +607,8 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
|
||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public D3D12ResourceAllocator(
|
||||
IFenceSynchronizer fenceSynchronizer,
|
||||
D3D12RenderDevice device,
|
||||
@@ -610,14 +618,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
{
|
||||
var desc = new D3D12MA_ALLOCATOR_DESC
|
||||
{
|
||||
pAdapter = (IDXGIAdapter*)device.Adapter,
|
||||
pDevice = (ID3D12Device*)device.NativeDevice,
|
||||
pAdapter = (IDXGIAdapter*)device.Adapter.Get(),
|
||||
pDevice = (ID3D12Device*)device.NativeDevice.Get(),
|
||||
Flags = D3D12MA_ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA_ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED,
|
||||
};
|
||||
|
||||
D3D12MA_Allocator* pAllocator = default;
|
||||
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
||||
nativeObject.Attach(pAllocator);
|
||||
_d3d12MA.Attach(pAllocator);
|
||||
|
||||
_fenceSynchronizer = fenceSynchronizer;
|
||||
_device = device;
|
||||
@@ -648,7 +656,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
|
||||
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
CheckTexture2DSize(desc.Width, desc.Height);
|
||||
|
||||
@@ -706,7 +714,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var initialState = DetermineInitialTextureState(desc.Usage);
|
||||
|
||||
D3D12MA_Allocation* pAllocation = default;
|
||||
ThrowIfFailed(nativeObject.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
||||
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
||||
|
||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
||||
@@ -717,7 +725,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
|
||||
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
|
||||
|
||||
_device.NativeDevice->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle);
|
||||
}
|
||||
|
||||
if (desc.Usage.HasFlag(TextureUsage.RenderTarget))
|
||||
@@ -726,7 +734,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.rtv);
|
||||
var rtvDesc = CreateRtvDesc(pAllocation->GetResource());
|
||||
|
||||
_device.NativeDevice->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle);
|
||||
}
|
||||
|
||||
if (desc.Usage.HasFlag(TextureUsage.DepthStencil))
|
||||
@@ -735,7 +743,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv);
|
||||
var dsvDesc = CreateDsvDesc(pAllocation->GetResource());
|
||||
|
||||
_device.NativeDevice->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle);
|
||||
}
|
||||
|
||||
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
||||
@@ -744,7 +752,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
||||
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
||||
|
||||
_device.NativeDevice->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
||||
}
|
||||
|
||||
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
|
||||
@@ -754,24 +762,27 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
|
||||
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool isTemp = false)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var textureDesc = desc.ToTextureDescripton();
|
||||
return CreateTexture(ref textureDesc, isTemp);
|
||||
return CreateTexture(in textureDesc, isTemp);
|
||||
}
|
||||
|
||||
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
CheckBufferSize(desc.Size);
|
||||
|
||||
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
|
||||
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
|
||||
if (isRaw)
|
||||
var alignedSize = desc.Size;
|
||||
if (desc.Usage.HasFlag(BufferUsage.Constant))
|
||||
{
|
||||
resourceDescription.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
// D3D12 CBV size must be 256-byte aligned
|
||||
alignedSize = (uint)(desc.Size + 255) & ~255u;
|
||||
}
|
||||
|
||||
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(alignedSize, ConvertBufferUsage(desc.Usage));
|
||||
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
|
||||
|
||||
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
||||
{
|
||||
HeapType = ConvertMemoryType(desc.MemoryType),
|
||||
@@ -781,42 +792,41 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
var initialState = DetermineInitialBufferState(desc.Usage, desc.MemoryType);
|
||||
|
||||
D3D12MA_Allocation* pAllocation = default;
|
||||
ThrowIfFailed(nativeObject.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
||||
var iid = IID.IID_NULL;
|
||||
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, &iid, null));
|
||||
|
||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||
var pResource = pAllocation->GetResource();
|
||||
|
||||
if (desc.Usage.HasFlag(BufferUsage.Constant))
|
||||
{
|
||||
// D3D12 CBV size must be 256-byte aligned
|
||||
var alignedSize = (uint)(desc.Size + 255) & ~255u;
|
||||
|
||||
resourceDescriptor.cbv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.cbv);
|
||||
var cbvDesc = new D3D12_CONSTANT_BUFFER_VIEW_DESC
|
||||
{
|
||||
BufferLocation = pResource->GetGPUVirtualAddress(),
|
||||
SizeInBytes = alignedSize
|
||||
SizeInBytes = (uint)alignedSize
|
||||
};
|
||||
|
||||
_device.NativeDevice->CreateConstantBufferView(&cbvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.cbv));
|
||||
_device.NativeDevice.Get()->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||
}
|
||||
|
||||
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
|
||||
{
|
||||
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.srv);
|
||||
var srvDesc = CreateBufferSrvDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
||||
|
||||
_device.NativeDevice->CreateShaderResourceView(pResource, &srvDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateShaderResourceView(pResource, &srvDesc, cpuHandle);
|
||||
}
|
||||
|
||||
if (desc.Usage.HasFlag(BufferUsage.UnorderedAccess))
|
||||
{
|
||||
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav);
|
||||
var uavDesc = CreateBufferUavDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
||||
|
||||
_device.NativeDevice->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle);
|
||||
_device.NativeDevice.Get()->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle);
|
||||
}
|
||||
|
||||
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
|
||||
@@ -825,7 +835,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
|
||||
public Handle<GraphicsBuffer> CreateUploadBuffer(ulong size, bool isTemp = true)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var desc = new BufferDesc
|
||||
{
|
||||
@@ -834,18 +844,18 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
MemoryType = ResourceMemoryType.Upload,
|
||||
};
|
||||
|
||||
return CreateBuffer(ref desc, isTemp);
|
||||
return CreateBuffer(in desc, isTemp);
|
||||
}
|
||||
|
||||
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var vertexBufferDesc = new BufferDesc
|
||||
{
|
||||
Size = (uint)(vertices.Count * Unsafe.SizeOf<Vertex>()),
|
||||
Stride = (uint)Unsafe.SizeOf<Vertex>(),
|
||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource,
|
||||
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
||||
Stride = (uint)sizeof(Vertex),
|
||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
};
|
||||
|
||||
@@ -853,37 +863,47 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
{
|
||||
Size = (uint)(indices.Count * sizeof(uint)),
|
||||
Stride = sizeof(uint),
|
||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource,
|
||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
};
|
||||
|
||||
var vertexBuffer = CreateBuffer(ref vertexBufferDesc);
|
||||
var indexBuffer = CreateBuffer(ref indexBufferDesc);
|
||||
var objectBufferDesc = new BufferDesc
|
||||
{
|
||||
Size = (uint)sizeof(PerObjectData),
|
||||
Stride = (uint)sizeof(PerObjectData),
|
||||
Usage = BufferUsage.Constant,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
};
|
||||
|
||||
var vertexBuffer = CreateBuffer(in vertexBufferDesc);
|
||||
var indexBuffer = CreateBuffer(in indexBufferDesc);
|
||||
var objectBuffer = CreateBuffer(in objectBufferDesc);
|
||||
|
||||
var data = new Mesh
|
||||
{
|
||||
vertices = vertices,
|
||||
indices = indices,
|
||||
vertexBuffer = vertexBuffer,
|
||||
indexBuffer = indexBuffer,
|
||||
Vertices = vertices,
|
||||
Indices = indices,
|
||||
VertexBuffer = vertexBuffer,
|
||||
IndexBuffer = indexBuffer,
|
||||
ObjectDataBuffer = objectBuffer,
|
||||
};
|
||||
|
||||
return _resourceDatabase.AddMesh(ref data);
|
||||
return _resourceDatabase.AddMesh(in data);
|
||||
}
|
||||
|
||||
public Handle<Material> CreateMaterial(Identifier<Shader> shader)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var material = new Material();
|
||||
material.SetShader(shader, this, _resourceDatabase);
|
||||
|
||||
return _resourceDatabase.AddMaterial(ref material);
|
||||
return _resourceDatabase.AddMaterial(in material);
|
||||
}
|
||||
|
||||
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var shader = new Shader(descriptor);
|
||||
foreach (var pass in descriptor.passes)
|
||||
@@ -893,6 +913,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Cache the pass key because we hash it multiple times right now.
|
||||
var passKey = new ShaderPassKey(fullPass.Identifier);
|
||||
var cbr = _pipelineLibrary.GetCBufferInfo(passKey);
|
||||
if (cbr.Status != ResultStatus.Success)
|
||||
@@ -908,7 +929,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
|
||||
public void ReleaseTempResources()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
while (_temResources.Count > 0)
|
||||
{
|
||||
@@ -933,9 +954,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -952,8 +973,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
||||
_resourceDatabase.ReleaseResource(handle);
|
||||
}
|
||||
|
||||
_d3d12MA.Dispose();
|
||||
_temResources.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,10 @@ using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
{
|
||||
internal unsafe struct ResourceRecord
|
||||
{
|
||||
@@ -56,12 +55,12 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public ResourceRecord(ID3D12Resource* resource, ResourceState state)
|
||||
public ResourceRecord(ID3D12Resource* resource, ResourceState state, ResourceViewGroup viewGroup)
|
||||
{
|
||||
this.resourceUnion = new ResourceUnion(resource);
|
||||
this.isExternal = true;
|
||||
|
||||
this.viewGroup = default;
|
||||
this.viewGroup = viewGroup;
|
||||
this.cpuFenceValue = ~0u;
|
||||
this.state = state;
|
||||
this.desc = ResourceDesc.FromD3D12(resource->GetDesc());
|
||||
@@ -80,13 +79,13 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
{
|
||||
refCount = resourceUnion.allocation.Get()->Release();
|
||||
}
|
||||
|
||||
resourceUnion = default;
|
||||
viewGroup = default;
|
||||
}
|
||||
|
||||
descriptorAllocator.Release(viewGroup);
|
||||
|
||||
resourceUnion = default;
|
||||
viewGroup = default;
|
||||
|
||||
return refCount;
|
||||
}
|
||||
}
|
||||
@@ -107,15 +106,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
|
||||
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
||||
{
|
||||
_resources = new(64, Allocator.Persistent, AllocationOption.Clear);
|
||||
_resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear);
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
_resourceName = new(64);
|
||||
_resourceName = new Dictionary<Handle<GPUResource>, string>(64);
|
||||
#endif
|
||||
|
||||
_meshes = new(64, Allocator.Persistent, AllocationOption.Clear);
|
||||
_materials = new(16, Allocator.Persistent, AllocationOption.Clear);
|
||||
_shaders = new(16);
|
||||
_shaderPasses = new(16);
|
||||
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear);
|
||||
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear);
|
||||
_shaders = new DynamicArray<Shader?>(16);
|
||||
_shaderPasses = new Dictionary<ShaderPassKey, ShaderPass>(16);
|
||||
|
||||
_descriptorAllocator = descriptorAllocator;
|
||||
}
|
||||
@@ -132,11 +131,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
resource = default!;
|
||||
}
|
||||
|
||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, string? name = null)
|
||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var id = _resources.Add(new ResourceRecord(pResource, initialState), out var generation);
|
||||
var id = _resources.Add(new ResourceRecord(pResource, initialState, viewGroup), out var generation);
|
||||
var handle = new Handle<GPUResource>(id, generation);
|
||||
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
@@ -172,7 +171,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
return _resources.Contains(handle.id, handle.generation);
|
||||
}
|
||||
|
||||
public ref ResourceRecord GetResourceInfo(Handle<GPUResource> handle)
|
||||
public ref ResourceRecord GetResourceRecord(Handle<GPUResource> handle)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
@@ -191,11 +190,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
||||
}
|
||||
|
||||
public unsafe ID3D12Resource* GetResource(Handle<GPUResource> handle)
|
||||
public unsafe SharedPtr<ID3D12Resource> GetResource(Handle<GPUResource> handle)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
ref var info = ref GetResourceInfo(handle);
|
||||
ref var info = ref GetResourceRecord(handle);
|
||||
if (!info.Allocated)
|
||||
{
|
||||
return null;
|
||||
@@ -207,7 +206,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
public ResourceState GetResourceState(Handle<GPUResource> handle)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
return GetResourceInfo(handle).state;
|
||||
return GetResourceRecord(handle).state;
|
||||
}
|
||||
|
||||
public void SetResourceState(Handle<GPUResource> handle, ResourceState state)
|
||||
@@ -226,7 +225,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
public ResourceDesc GetResourceDescription(Handle<GPUResource> handle)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
return GetResourceInfo(handle).desc;
|
||||
return GetResourceRecord(handle).desc;
|
||||
}
|
||||
|
||||
public int GetBindlessIndex(Handle<GPUResource> handle)
|
||||
@@ -273,10 +272,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
var refCount = info.Release(_descriptorAllocator);
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
_resourceName.Remove(handle, out var name);
|
||||
if (refCount > 0)
|
||||
{
|
||||
throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
|
||||
}
|
||||
//if (refCount > 0)
|
||||
//{
|
||||
// throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
|
||||
//}
|
||||
//Debug.Assert(refCount == 0, "Resource released with non-zero reference count.");
|
||||
#endif
|
||||
|
||||
_resources.Remove(handle.id, handle.generation);
|
||||
@@ -435,10 +435,9 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
[Conditional("DEBUG"), Conditional("GHOST_EDITOR")]
|
||||
static void ThrowMemoryLeakException(string resourceType, int count)
|
||||
{
|
||||
throw new InvalidOperationException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing.");
|
||||
throw new MemoryLeakException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing.");
|
||||
}
|
||||
|
||||
if (_disposed)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -17,12 +18,19 @@ namespace Ghost.Graphics.D3D12;
|
||||
/// <summary>
|
||||
/// D3D12 implementation of swap chain interface
|
||||
/// </summary>
|
||||
internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapChain
|
||||
internal unsafe class D3D12SwapChain : ISwapChain
|
||||
{
|
||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||
private readonly D3D12RenderDevice _renderDevice;
|
||||
|
||||
private UniquePtr<IDXGISwapChain4> _swapChain;
|
||||
private UnsafeArray<Handle<Texture>> _backBuffers;
|
||||
|
||||
private object? _compositionSurface;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public uint Width
|
||||
{
|
||||
get; private set;
|
||||
@@ -38,9 +46,11 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
get;
|
||||
}
|
||||
|
||||
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, IDXGIFactory7* pFactory, ID3D12CommandQueue* pCommandQueue, SwapChainDesc desc)
|
||||
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
|
||||
{
|
||||
_resourceDatabase = resourceDatabase;
|
||||
_descriptorAllocator = descriptorAllocator;
|
||||
_renderDevice = device;
|
||||
|
||||
_backBuffers = new UnsafeArray<Handle<Texture>>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
|
||||
|
||||
@@ -48,11 +58,18 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
Height = desc.height;
|
||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
|
||||
|
||||
CreateSwapChain(pFactory, pCommandQueue, desc);
|
||||
CreateSwapChain(desc);
|
||||
CreateBackBuffers();
|
||||
|
||||
_compositionSurface = desc.target.compositionSurface;
|
||||
}
|
||||
|
||||
private void CreateSwapChain(IDXGIFactory7* pFactory, ID3D12CommandQueue* commandQueue, SwapChainDesc desc)
|
||||
~D3D12SwapChain()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void CreateSwapChain(SwapChainDesc desc)
|
||||
{
|
||||
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
||||
{
|
||||
@@ -71,10 +88,13 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
|
||||
IDXGISwapChain1* pTempSwapChain = default;
|
||||
|
||||
var pFactory = _renderDevice.DXGIFactory.Get();
|
||||
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
|
||||
|
||||
switch (desc.target.type)
|
||||
{
|
||||
case SwapChainTargetType.Composition:
|
||||
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)commandQueue, &swapChainDesc, null, &pTempSwapChain));
|
||||
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
|
||||
|
||||
// Set the composition surface
|
||||
if (desc.target.compositionSurface != null)
|
||||
@@ -91,7 +111,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
};
|
||||
|
||||
pFactory->CreateSwapChainForHwnd(
|
||||
(IUnknown*)commandQueue,
|
||||
(IUnknown*)pCommandQueue,
|
||||
new HWND(desc.target.windowHandle.ToPointer()),
|
||||
&swapChainDesc,
|
||||
&swapChainFullscreenDesc,
|
||||
@@ -107,7 +127,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
pTempSwapChain->QueryInterface(__uuidof(pSwapChain), (void**)&pSwapChain);
|
||||
pTempSwapChain->Release();
|
||||
|
||||
nativeObject.Attach(pSwapChain);
|
||||
_swapChain.Attach(pSwapChain);
|
||||
}
|
||||
|
||||
private void CreateBackBuffers()
|
||||
@@ -115,33 +135,37 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
for (uint i = 0; i < BufferCount; i++)
|
||||
{
|
||||
ID3D12Resource* pBackBuffer = default;
|
||||
nativeObject.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer);
|
||||
ThrowIfFailed(_swapChain.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer));
|
||||
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
|
||||
|
||||
_backBuffers[i] = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present).AsTexture();
|
||||
var rtv = _descriptorAllocator.AllocateRTV();
|
||||
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
|
||||
|
||||
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, new ResourceViewGroup() { rtv = rtv });
|
||||
_backBuffers[i] = handle.AsTexture();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Handle<Texture> GetCurrentBackBuffer()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _backBuffers[nativeObject.Get()->GetCurrentBackBufferIndex()];
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
return _backBuffers[_swapChain.Get()->GetCurrentBackBufferIndex()];
|
||||
}
|
||||
|
||||
public void Present(bool vsync = true)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var presentFlags = 0u;
|
||||
var syncInterval = vsync ? 1u : 0u;
|
||||
|
||||
ThrowIfFailed(nativeObject.Get()->Present(syncInterval, presentFlags));
|
||||
ThrowIfFailed(_swapChain.Get()->Present(syncInterval, presentFlags));
|
||||
}
|
||||
|
||||
public void Resize(uint width, uint height)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (Width == width && Height == height)
|
||||
{
|
||||
@@ -155,7 +179,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
}
|
||||
|
||||
// Resize the swap chain
|
||||
if (nativeObject.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED)
|
||||
if (_swapChain.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to resize swap chain buffers.");
|
||||
}
|
||||
@@ -167,20 +191,28 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
||||
CreateBackBuffers();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_compositionSurface != null)
|
||||
{
|
||||
using var panelNative = ISwapChainPanelNative.FromSwapChainPanel(_compositionSurface);
|
||||
panelNative.SetSwapChain(IntPtr.Zero);
|
||||
}
|
||||
|
||||
for (var i = 0; i < _backBuffers.Count; i++)
|
||||
{
|
||||
_resourceDatabase.ReleaseResource(_backBuffers[i].AsResource());
|
||||
}
|
||||
|
||||
_backBuffers.Dispose();
|
||||
_swapChain.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
HeapType = type;
|
||||
NumDescriptors = numDescriptors;
|
||||
ShaderVisible = type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||
Stride = device.NativeDevice->GetDescriptorHandleIncrementSize(type);
|
||||
Stride = device.NativeDevice.Get()->GetDescriptorHandleIncrementSize(type);
|
||||
|
||||
_dynamicHeapStart = Math.Clamp(dynamicHeapStart, 0, numDescriptors);
|
||||
_currentDynamicOffset = 0;
|
||||
@@ -254,14 +254,14 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
}
|
||||
|
||||
var newLocation = AllocateDescriptors(count);
|
||||
_device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType);
|
||||
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType);
|
||||
|
||||
return newLocation;
|
||||
}
|
||||
|
||||
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
|
||||
{
|
||||
_device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
||||
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
||||
}
|
||||
|
||||
private bool AllocateResources(int numDescriptors)
|
||||
@@ -279,7 +279,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
};
|
||||
|
||||
ID3D12DescriptorHeap* pHeap = default;
|
||||
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap);
|
||||
var hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap);
|
||||
if (hr.FAILED)
|
||||
{
|
||||
return false;
|
||||
@@ -291,11 +291,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
|
||||
if (!_allocatedDescriptors.IsCreated)
|
||||
{
|
||||
_allocatedDescriptors = new UnsafeArray<bool>(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||
_allocatedDescriptors = new UnsafeArray<bool>(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear);
|
||||
}
|
||||
else
|
||||
{
|
||||
_allocatedDescriptors.Resize(numDescriptors);
|
||||
_allocatedDescriptors.Resize(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear);
|
||||
}
|
||||
|
||||
if (ShaderVisible)
|
||||
@@ -303,7 +303,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
ID3D12DescriptorHeap* pShaderVisibleHeap = default;
|
||||
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap);
|
||||
hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap);
|
||||
if (hr.FAILED)
|
||||
{
|
||||
return false;
|
||||
@@ -332,11 +332,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
_device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||
|
||||
if (_shaderVisibleHeap.Get() != null)
|
||||
{
|
||||
_device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -350,12 +350,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
#if DEBUG
|
||||
if (NumAllocatedDescriptors > 0)
|
||||
{
|
||||
Debug.WriteLine($"Warning: Descriptor heap of type {HeapType} is being disposed with {NumAllocatedDescriptors} allocated descriptors.");
|
||||
}
|
||||
#endif
|
||||
Debug.Assert(NumAllocatedDescriptors == 0);
|
||||
|
||||
_heap.Dispose();
|
||||
_shaderVisibleHeap.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user