Refactor and enhance graphics and audio systems

Updated target frameworks to .NET 10.0 across multiple projects for compatibility with the latest features. Refactored namespaces and introduced new classes for shader descriptors, FMOD integration, and DirectX 12 utilities using TerraFX. Replaced `Win32` bindings with TerraFX equivalents for DirectX 12. Added a C# wrapper for FMOD Studio API, including DSP and error handling. Enhanced entity queries, component storage, and query filters for better performance and type safety. Introduced new test projects and updated the solution structure. Added `meshoptimizer` bindings and integrated `meshoptimizer_native.dll`. Improved code readability, maintainability, and performance.
This commit is contained in:
2025-10-09 05:16:28 +09:00
parent 01a850ff94
commit 682200cbf1
126 changed files with 25587 additions and 3247 deletions

View File

@@ -1,14 +1,14 @@
using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.Data;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Utilities;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using Win32;
using Win32.Graphics.Direct3D;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi.Common;
using Win32.Numerics;
using static TerraFX.Aliases.D3D12_Alias;
using static TerraFX.Aliases.DXGI_Alias;
using static TerraFX.Aliases.D3D_Alias;
namespace Ghost.Graphics.D3D12;
@@ -20,7 +20,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
private ComPtr<ID3D12CommandAllocator> _allocator;
private ComPtr<ID3D12GraphicsCommandList10> _commandList;
private readonly D3D12PipelineLibrary _stateController;
private readonly D3D12PipelineLibrary _pipelineLibrary;
private readonly D3D12ResourceDatabase _resourceDatabase;
private readonly D3D12ResourceAllocator _resourceAllocator;
private readonly D3D12DescriptorAllocator _descriptorAllocator;
@@ -48,9 +48,9 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var commandListType = ConvertCommandBufferType(type);
device.NativeDevice->CreateCommandAllocator(commandListType, __uuidof<ID3D12CommandAllocator>(), _allocator.GetVoidAddressOf());
device.NativeDevice->CreateCommandList1(0u, commandListType, CommandListFlags.None, __uuidof<ID3D12GraphicsCommandList10>(), _commandList.GetVoidAddressOf());
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof<ID3D12GraphicsCommandList10>(), _commandList.GetVoidAddressOf());
_stateController = stateController;
_pipelineLibrary = stateController;
_resourceDatabase = resourceDatabase;
_resourceAllocator = resourceAllocator;
_descriptorAllocator = descriptorAllocator;
@@ -113,7 +113,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording();
IncrementCommandCount();
var rtvHandles = stackalloc CpuDescriptorHandle[renderTargets.Length];
var rtvHandles = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[renderTargets.Length];
for (var i = 0; i < renderTargets.Length; i++)
{
var handle = renderTargets[i];
@@ -126,13 +126,13 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
rtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
}
var dsvHandle = stackalloc CpuDescriptorHandle[depthTarget.IsValid ? 1 : 0];
var dsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
if (dsvHandle != null)
{
*dsvHandle = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).descriptor.dsv);
}
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, rtvHandles, Bool32.False, dsvHandle);
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, rtvHandles, FALSE, dsvHandle);
}
public void BeginRenderPass(Handle<Texture> renderTarget, Handle<Texture> depthTarget, Color128 clearColor)
@@ -155,7 +155,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording();
IncrementCommandCount();
var d3d12Viewport = new Viewport(viewport.width, viewport.height, viewport.x, viewport.y, viewport.minDepth, viewport.maxDepth);
var d3d12Viewport = new D3D12_VIEWPORT(viewport.width, viewport.height, viewport.x, viewport.y, viewport.minDepth, viewport.maxDepth);
_commandList.Get()->RSSetViewports(1, &d3d12Viewport);
}
@@ -165,7 +165,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ThrowIfNotRecording();
IncrementCommandCount();
var d3d12Rect = new Rect((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom);
var d3d12Rect = new RECT((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom);
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
}
@@ -176,9 +176,10 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
IncrementCommandCount();
var d3d12Resource = _resourceDatabase.GetResource(resource);
_commandList.Get()->ResourceBarrierTransition(d3d12Resource,
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
before.ToD3D12States(), after.ToD3D12States());
_commandList.Get()->ResourceBarrier(1, &barrier);
}
public void SetRootSignature(IRootSignature rootSignature)
@@ -200,7 +201,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
IncrementCommandCount();
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
var vbView = new VertexBufferView
var vbView = new D3D12_VERTEX_BUFFER_VIEW
{
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
@@ -217,11 +218,11 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
IncrementCommandCount();
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
var ibView = new IndexBufferView
var ibView = new D3D12_INDEX_BUFFER_VIEW
{
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
Format = type == IndexType.UInt16 ? Format.R16Uint : Format.R32Uint
Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT
};
_commandList.Get()->IASetIndexBuffer(&ibView);
@@ -256,36 +257,36 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material);
ref var shaderRef = ref _resourceDatabase.GetShaderReference(materialRef.Shader);
var shaderPipeline = _stateController.GetShaderPipeline(materialRef.Shader);
var shaderPipeline = _pipelineLibrary.GetShaderPipeline(materialRef.Shader);
if (shaderPipeline is not D3D12ShaderPipeline d3d12Pipeline)
{
throw new InvalidOperationException("Shader pipeline is not compiled or invalid");
}
_commandList.Get()->SetPipelineState(d3d12Pipeline.pipelineState.Get());
_commandList.Get()->SetGraphicsRootSignature(d3d12Pipeline.rootSignature.Get());
_commandList.Get()->SetGraphicsRootSignature(_pipelineLibrary.DefaultRootSignature);
// Set descriptor heaps - CRUCIAL: Use the specialized bindless heap for SM 6.6
var heaps = stackalloc ID3D12DescriptorHeap*[2];
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Specialized bindless heap
heaps[1] = d3d12Pipeline.samplerHeap.Get(); // Sampler heap from shader
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
_commandList.Get()->SetDescriptorHeaps(2, heaps);
var rootParamIndex = 0u;
foreach (var cbufferInfo in shaderRef.ConstantBuffers)
foreach (var cbufferInfo in shaderRef.PerMaterialBufferInfo)
{
ref var cache = ref materialRef._cBufferCaches[(int)cbufferInfo.RegisterSlot];
ref var cache = ref materialRef._materialPropertiesCache[(int)cbufferInfo.RegisterSlot];
var resource = _resourceDatabase.GetResource(cache.GpuResource.AsResource());
_commandList.Get()->SetGraphicsRootConstantBufferView(rootParamIndex++, resource->GetGPUVirtualAddress());
}
var samplerGpuHandle = d3d12Pipeline.samplerHeap.Get()->GetGPUDescriptorHandleForHeapStart();
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
// For fully bindless rendering, we don't use the Input Assembler stage
// Instead, we use instanced drawing where each "instance" represents a triangle
// The shader will use SV_InstanceID to index into the index buffer and then into the vertex buffer
_commandList.Get()->IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
_commandList.Get()->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Draw without vertex/index buffers - use instanced drawing
// Each instance represents a triangle (3 vertices)
@@ -341,10 +342,10 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize);
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
var d3d12Subresources = stackalloc SubresourceData[subresources.Length];
var d3d12Subresources = stackalloc D3D12_SUBRESOURCE_DATA[subresources.Length];
for (var i = 0; i < subresources.Length; i++)
{
d3d12Subresources[i] = new SubresourceData
d3d12Subresources[i] = new D3D12_SUBRESOURCE_DATA
{
pData = subresources[i].pData,
RowPitch = subresources[i].rowPitch,
@@ -385,13 +386,13 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
}
}
private static CommandListType ConvertCommandBufferType(CommandBufferType type)
private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type)
{
return type switch
{
CommandBufferType.Graphics => CommandListType.Direct,
CommandBufferType.Compute => CommandListType.Compute,
CommandBufferType.Copy => CommandListType.Copy,
CommandBufferType.Graphics => D3D12_COMMAND_LIST_TYPE_DIRECT,
CommandBufferType.Compute => D3D12_COMMAND_LIST_TYPE_COMPUTE,
CommandBufferType.Copy => D3D12_COMMAND_LIST_TYPE_COPY,
_ => throw new ArgumentException($"Unknown command buffer type: {type}")
};
}

View File

@@ -1,8 +1,7 @@
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Win32;
using Win32.Graphics.Direct3D12;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Ghost.Graphics.D3D12;
@@ -29,11 +28,11 @@ internal unsafe class D3D12CommandQueue : ICommandQueue
_fenceEvent = new AutoResetEvent(false);
_fenceValue = 0;
var queueDesc = new CommandQueueDescription
var queueDesc = new D3D12_COMMAND_QUEUE_DESC
{
Type = ConvertCommandQueueType(type),
Priority = (int)CommandQueuePriority.Normal,
Flags = CommandQueueFlags.None,
Priority = (int)D3D12_COMMAND_QUEUE_PRIORITY.D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE,
};
fixed (void* queuePtr = &_queue)
@@ -41,7 +40,7 @@ internal unsafe class D3D12CommandQueue : ICommandQueue
pDevice->CreateCommandQueue(&queueDesc, __uuidof<ID3D12CommandQueue>(), (void**)queuePtr);
}
pDevice->CreateFence(0, FenceFlags.None, __uuidof<ID3D12Fence1>(), _fence.GetVoidAddressOf());
pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof<ID3D12Fence1>(), _fence.GetVoidAddressOf());
}
~D3D12CommandQueue()
@@ -120,8 +119,8 @@ internal unsafe class D3D12CommandQueue : ICommandQueue
{
if (_fence.Get()->GetCompletedValue() < value)
{
var handle = new Handle((void*)_fenceEvent.SafeWaitHandle.DangerousGetHandle());
if (_fence.Get()->SetEventOnCompletion(value, handle).Success)
var handle = new HANDLE((void*)_fenceEvent.SafeWaitHandle.DangerousGetHandle());
if (_fence.Get()->SetEventOnCompletion(value, handle).SUCCEEDED)
{
_fenceEvent.WaitOne();
}
@@ -139,13 +138,13 @@ internal unsafe class D3D12CommandQueue : ICommandQueue
WaitForValue(fenceValue);
}
private static CommandListType ConvertCommandQueueType(CommandQueueType type)
private static D3D12_COMMAND_LIST_TYPE ConvertCommandQueueType(CommandQueueType type)
{
return type switch
{
CommandQueueType.Graphics => CommandListType.Direct,
CommandQueueType.Compute => CommandListType.Compute,
CommandQueueType.Copy => CommandListType.Copy,
CommandQueueType.Graphics => D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_DIRECT,
CommandQueueType.Compute => D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_COMPUTE,
CommandQueueType.Copy => D3D12_COMMAND_LIST_TYPE.D3D12_COMMAND_LIST_TYPE_COPY,
_ => throw new ArgumentException($"Unknown command queue type: {type}")
};
}

View File

@@ -1,6 +1,8 @@
using Win32;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi;
using Ghost.Graphics.D3D12.Utilities;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12;
@@ -19,13 +21,13 @@ internal unsafe class D3D12DebugLayer
_dxgiDebug.Get()->EnableLeakTrackingForThread();
DXGIGetDebugInterface1(0u, __uuidof<IDXGIInfoQueue>(), _dxgiInfoQueue.GetVoidAddressOf());
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, InfoQueueMessageSeverity.Error, true);
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, InfoQueueMessageSeverity.Corruption, true);
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
}
public void Dispose()
{
_dxgiDebug.Get()->ReportLiveObjects(DXGI_DEBUG_ALL, ReportLiveObjectFlags.All);
_dxgiDebug.Get()->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL | DXGI_DEBUG_RLO_IGNORE_INTERNAL);
_d3d12Debug.Dispose();
_dxgiDebug.Dispose();

View File

@@ -1,7 +1,9 @@
using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
using System.Runtime.CompilerServices;
using Win32.Graphics.Direct3D12;
using TerraFX.Interop.DirectX;
using static TerraFX.Aliases.D3D12_Alias;
namespace Ghost.Graphics.D3D12;
@@ -19,10 +21,10 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
public unsafe D3D12DescriptorAllocator(D3D12RenderDevice device, int initialRtvCount = 256, int initialDsvCount = 256, int initialSrvCount = 200_000, int initialSamplerCount = 256)
{
_rtvHeap = new D3D12DescriptorHeap("rtv", device, DescriptorHeapType.Rtv, initialRtvCount, initialRtvCount / 2);
_dsvHeap = new D3D12DescriptorHeap("dsv", device, DescriptorHeapType.Dsv, initialDsvCount, initialDsvCount / 2);
_cbvSrvUavHeap = new D3D12DescriptorHeap("srv", device, DescriptorHeapType.CbvSrvUav, initialSrvCount, initialSrvCount /2);
_samplerHeap = new D3D12DescriptorHeap("sampler", device, DescriptorHeapType.Sampler, initialSamplerCount, initialSamplerCount);
_rtvHeap = new D3D12DescriptorHeap("rtv", device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, initialRtvCount, initialRtvCount / 2);
_dsvHeap = new D3D12DescriptorHeap("dsv", device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, initialDsvCount, initialDsvCount / 2);
_cbvSrvUavHeap = new D3D12DescriptorHeap("srv", device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, initialSrvCount, initialSrvCount /2);
_samplerHeap = new D3D12DescriptorHeap("sampler", device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, initialSamplerCount, initialSamplerCount);
}
~D3D12DescriptorAllocator()
@@ -66,7 +68,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CpuDescriptorHandle GetCpuHandle(Identifier<RTVDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<RTVDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _rtvHeap.GetCpuHandle(descriptor.value);
@@ -151,7 +153,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
return descriptors;
}
public CpuDescriptorHandle GetCpuHandle(Identifier<DSVDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<DSVDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _dsvHeap.GetCpuHandle(descriptor.value);
@@ -236,19 +238,19 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
return descriptors;
}
public CpuDescriptorHandle GetCpuHandle(Identifier<CbvSrvUavDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<CbvSrvUavDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetCpuHandle(descriptor.value);
}
public CpuDescriptorHandle GetCpuHandleShaderVisible(Identifier<CbvSrvUavDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<CbvSrvUavDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetCpuHandleShaderVisible(descriptor.value);
}
public GpuDescriptorHandle GetGpuHandle(Identifier<CbvSrvUavDesc> descriptor)
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<CbvSrvUavDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetGpuHandle(descriptor.value);
@@ -333,19 +335,19 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
return descriptors;
}
public CpuDescriptorHandle GetCpuHandle(Identifier<SamplerDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<SamplerDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetCpuHandle(descriptor.value);
}
public CpuDescriptorHandle GetCpuHandleShaderVisible(Identifier<SamplerDesc> descriptor)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<SamplerDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetCpuHandleShaderVisible(descriptor.value);
}
public GpuDescriptorHandle GetGpuHandle(Identifier<SamplerDesc> descriptor)
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<SamplerDesc> descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetGpuHandle(descriptor.value);
@@ -370,7 +372,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Release(D3D12ResourceDescriptor descriptor)
public void Release(ResourceViewGroup descriptor)
{
ObjectDisposedException.ThrowIf(_disposed, this);

View File

@@ -35,7 +35,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
_resourceDatabase = new(_descriptorAllocator);
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase);
_stateController = new(_device, _resourceDatabase);
_stateController = new(_device, _resourceDatabase, null);
_copyCommandBuffer = new(
_device,
_stateController,

View File

@@ -1,15 +1,17 @@
#undef USE_TRANDITIONAL_BINDLESS
#undef USE_TRADITIONAL_BINDLESS
using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.Data;
using Ghost.Graphics.RHI;
using Ghost.Graphics.Utilities;
using System.Runtime.InteropServices;
using Win32;
using Win32.Graphics.Direct3D;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi.Common;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using Misaki.HighPerformance.LowLevel.Utilities;
using static TerraFX.Aliases.D3D12_Alias;
using static TerraFX.Aliases.D3D_Alias;
using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12;
@@ -36,47 +38,6 @@ internal class D3D12ShaderPipeline : IShaderPipeline, IDisposable
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal unsafe struct D3D12GraphicsPipelineStream
{
public PipelineStateSubObjectType rootSignatureType;
public ID3D12RootSignature* pRootSignature;
public PipelineStateSubObjectType vsType;
public ShaderBytecode vs;
public PipelineStateSubObjectType psType;
public ShaderBytecode ps;
public PipelineStateSubObjectType rasterizerType;
public RasterizerDescription rasterizer;
public PipelineStateSubObjectType blendType;
public BlendDescription blend;
public PipelineStateSubObjectType depthStencilType;
public DepthStencilDescription depthStencil;
public PipelineStateSubObjectType topologyType;
public PrimitiveTopologyType primitiveTopology;
public PipelineStateSubObjectType rtvFormatType;
public RtFormatArray rtvFormats;
public PipelineStateSubObjectType dsvFormatType;
public Format dsvFormat;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal unsafe struct ComputePipelineStream
{
public PipelineStateSubObjectType rootSignatureType;
public ID3D12RootSignature* pRootSignature;
public PipelineStateSubObjectType csType;
public ShaderBytecode cs;
}
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
{
private readonly D3D12RenderDevice _device;
@@ -87,6 +48,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
private readonly Dictionary<Identifier<Shader>, D3D12ShaderPipeline> _shaderPipelines;
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
public D3D12PipelineLibrary(D3D12RenderDevice device, D3D12ResourceDatabase resourceDatabase, string? cachePath)
{
_device = device;
@@ -115,7 +78,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
private void CreateDefaultRootSignature()
{
const int rootParamCount =
#if USE_TRANDITIONAL_BINDLESS
#if USE_TRADITIONAL_BINDLESS
6
#else
4
@@ -124,93 +87,85 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
_defaultRootSignature = default;
// The layout of the root signature is:
// - Global buffer (b0)
// - Per-view buffer (b1)
// - Per-object buffer (b2)
// - Per-instance buffer (b3)
// - Descriptor table for bindless textures (t0)
// - Descriptor table for bindless samplers (s0)
// NOTE: Since we are targeting SM 6.6, we can use ResourceDescriptorHeap and SamplerDescriptorHeap directly without needing to set up descriptor tables.
var rootParameters = stackalloc RootParameter1[rootParamCount];
rootParameters[0] = new RootParameter1
var rootParameters = stackalloc D3D12_ROOT_PARAMETER1[rootParamCount];
rootParameters[0] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.Cbv,
ShaderVisibility = ShaderVisibility.All,
Descriptor = new RootDescriptor1(0, 0), // b0
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
Descriptor = new D3D12_ROOT_DESCRIPTOR1(0, 0), // b0
};
rootParameters[1] = new RootParameter1
rootParameters[1] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.Cbv,
ShaderVisibility = ShaderVisibility.All,
Descriptor = new RootDescriptor1(1, 0), // b1
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
Descriptor = new D3D12_ROOT_DESCRIPTOR1(1, 0), // b1
};
rootParameters[2] = new RootParameter1
rootParameters[2] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.Cbv,
ShaderVisibility = ShaderVisibility.All,
Descriptor = new RootDescriptor1(2, 0), // b2
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
Descriptor = new D3D12_ROOT_DESCRIPTOR1(2, 0), // b2
};
rootParameters[3] = new RootParameter1
rootParameters[3] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.Cbv,
ShaderVisibility = ShaderVisibility.All,
Descriptor = new RootDescriptor1(3, 0), // b3
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
Descriptor = new D3D12_ROOT_DESCRIPTOR1(3, 0), // b3
};
#if USE_TRANDITIONAL_BINDLESS
#if USE_TRADITIONAL_BINDLESS
// Descriptor table for bindless textures
var srvRange = new DescriptorRange1(
DescriptorRangeType.Srv,
var srvRange = new D3D12_DESCRIPTOR_RANGE1(
D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
~0u,
0,
0,
DescriptorRangeFlags.DataVolatile);
D3D12_DESCRIPTOR_RANGE_FLAGS_DATA_VOLATILE);
rootParameters[4] = new RootParameter1
rootParameters[4] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.DescriptorTable,
ShaderVisibility = ShaderVisibility.All,
DescriptorTable = new RootDescriptorTable1(1, &srvRange)
ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
DescriptorTable = new D3D12_ROOT_DESCRIPTOR_TABLE1(1, &srvRange)
};
// Descriptor table for bindless samplers
var sampRange = new DescriptorRange1(
DescriptorRangeType.Sampler,
~0u,
var sampRange = new D3D12_DESCRIPTOR_RANGE1(
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
~0u,
0,
0,
DescriptorRangeFlags.DataVolatile);
D3D12_DESCRIPTOR_RANGE_FLAGS_DATA_VOLATILE);
rootParameters[5] = new RootParameter1
rootParameters[5] = new D3D12_ROOT_PARAMETER1
{
ParameterType = RootParameterType.DescriptorTable,
ShaderVisibility = ShaderVisibility.All,
DescriptorTable = new RootDescriptorTable1(1, &sampRange)
ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
DescriptorTable = new D3D12_ROOT_DESCRIPTOR_TABLE1(1, &sampRange)
};
#endif
var rootSignatureDesc = new RootSignatureDescription1
var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC1
{
NumParameters = rootParamCount,
pParameters = rootParameters,
NumStaticSamplers = 0,
pStaticSamplers = null,
Flags = RootSignatureFlags.AllowInputAssemblerInputLayout
#if !USE_TRANDITIONAL_BINDLESS
| RootSignatureFlags.CbvSrvUavHeapDirectlyIndexed
| RootSignatureFlags.SamplerHeapDirectlyIndexed
Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
#if !USE_TRADITIONAL_BINDLESS
| D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED
| D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED
#endif
};
var versionedDesc = new VersionedRootSignatureDescription
var versionedDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC
{
Version = RootSignatureVersion.V1_1,
Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
Desc_1_1 = rootSignatureDesc
};
@@ -218,7 +173,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
using ComPtr<ID3DBlob> error = default;
var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, signature.GetAddressOf(), error.GetAddressOf());
if (serializeResult.Failure)
if (serializeResult.FAILED)
{
var errorMsg = error.Get() != null ? Marshal.PtrToStringAnsi((nint)error.Get()->GetBufferPointer()) : "Unknown error";
throw new InvalidOperationException($"Failed to serialize default root signature: {errorMsg}");
@@ -230,12 +185,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
public void StorePipeline(string psoIdentifier, ID3D12PipelineState* pso)
{
_library.Get()->StorePipeline(psoIdentifier.AsSpan().GetPointer(), pso);
_library.Get()->StorePipeline(psoIdentifier.AsSpan().GetUnsafePtr(), pso);
}
public void* LoadGraphicsPipeline(string psoIdentifier)
{
if (_library.Get()->LoadGraphicsPipeline(psoIdentifier.AsSpan().GetPointer(), __uuidof<ID3D12PipelineState>(), out var pso).Failure)
if (_library.Get()->LoadGraphicsPipeline(psoIdentifier.AsSpan().GetUnsafePtr(), __uuidof<ID3D12PipelineState>(), out var pso).Failure)
{
return null;
}
@@ -266,20 +221,20 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
// Create PSO from SDL (Shader Definition Language) file
private void CreatePipelineStateObject(D3D12ShaderPipeline shaderPipeline)
{
var psoDesc = new GraphicsPipelineStateDescription
var psoDesc = new D3D12_GRAPHICS_PIPELINE_STATE_DESC
{
pRootSignature = _defaultRootSignature.Get(),
VS = new ShaderBytecode(shaderPipeline.vsResult.bytecode.GetUnsafePtr(), (nuint)shaderPipeline.vsResult.bytecode.Count),
PS = new ShaderBytecode(shaderPipeline.psResult.bytecode.GetUnsafePtr(), (nuint)shaderPipeline.vsResult.bytecode.Count),
VS = new D3D12_SHADER_BYTECODE(shaderPipeline.vsResult.bytecode.GetUnsafePtr(), (nuint)shaderPipeline.vsResult.bytecode.Count),
PS = new D3D12_SHADER_BYTECODE(shaderPipeline.psResult.bytecode.GetUnsafePtr(), (nuint)shaderPipeline.psResult.bytecode.Count),
InputLayout = D3D12PipelineResource.InputLayoutDescription,
RasterizerState = RasterizerDescription.CullNone,
BlendState = BlendDescription.Opaque,
DepthStencilState = DepthStencilDescription.Default,
RasterizerState = D3D12_RASTERIZER_DESC.CULL_NONE,
BlendState = D3D12_BLEND_DESC.OPAQUE,
DepthStencilState = D3D12_DEPTH_STENCIL_DESC.DEFAULT,
SampleMask = uint.MaxValue,
PrimitiveTopologyType = PrimitiveTopologyType.Triangle,
PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets = 1,
SampleDesc = new SampleDescription(1, 0),
DSVFormat = Format.Unknown,
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
DSVFormat = DXGI_FORMAT_UNKNOWN,
};
psoDesc.RTVFormats[0] = D3D12PipelineResource.SWAP_CHAIN_BACK_BUFFER_FORMAT;

View File

@@ -1,10 +1,9 @@
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using Win32;
using Win32.Graphics.Direct3D;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi;
using static TerraFX.Aliases.D3D_Alias;
using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12;
@@ -48,27 +47,27 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
private void InitializeDevice()
{
#if DEBUG
CreateDXGIFactory2(true, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
CreateDXGIFactory2(TRUE, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
#else
CreateDXGIFactory2(false, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
CreateDXGIFactory2(FALSE, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
#endif
using ComPtr<IDXGIAdapter1> adapter = default;
for (uint adapterIndex = 0;
_dxgiFactory.Get()->EnumAdapterByGpuPreference(adapterIndex, GpuPreference.HighPerformance, __uuidof<IDXGIAdapter1>(), adapter.ReleaseAndGetVoidAddressOf()).Success;
_dxgiFactory.Get()->EnumAdapterByGpuPreference(adapterIndex, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof<IDXGIAdapter1>(), adapter.ReleaseAndGetVoidAddressOf()).SUCCEEDED;
adapterIndex++)
{
AdapterDescription1 desc = default;
DXGI_ADAPTER_DESC1 desc = default;
adapter.Get()->GetDesc1(&desc);
// Don't select the Basic Render Driver adapter.
if ((desc.Flags & AdapterFlags.Software) != AdapterFlags.None)
if (desc.Flags.HasFlag(DXGI_ADAPTER_FLAG_SOFTWARE))
{
continue;
}
if (D3D12CreateDevice((IUnknown*)adapter.Get(), FeatureLevel.Level_12_0, __uuidof<ID3D12Device14>(), _device.GetVoidAddressOf()).Success)
if (D3D12CreateDevice((IUnknown*)adapter.Get(), D3D_FEATURE_LEVEL_12_0, __uuidof<ID3D12Device14>(), _device.GetVoidAddressOf()).SUCCEEDED)
{
_adapter = adapter.Move();
break;

View File

@@ -1,13 +1,15 @@
using Ghost.Core;
using Ghost.Core.Graphics;
using Ghost.Graphics.Data;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.CompilerServices;
using Win32.Graphics.D3D12MemoryAllocator;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi;
using Win32.Graphics.Dxgi.Common;
using static Win32.Graphics.D3D12MemoryAllocator.Apis;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.D3D12_Alias;
using static TerraFX.Aliases.D3D12MA_Alias;
using static TerraFX.Aliases.DXGI_Alias;
using static TerraFX.Interop.DirectX.D3D12MemAlloc;
namespace Ghost.Graphics.D3D12;
@@ -17,9 +19,9 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
private const uint _MAX_TEXTURE2D_DIMENSION = 16384u;
private const uint _MAX_TEXTURE3D_DIMENSION = 2048u;
private readonly ID3D12Device14* _device;
private ComPtr<D3D12MA_Allocator> _allocator;
private readonly Allocator _allocator;
private readonly D3D12RenderDevice _device;
private readonly RenderSystem _renderSystem;
private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly D3D12ResourceDatabase _resourceDatabase;
@@ -39,16 +41,16 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
public D3D12ResourceAllocator(RenderSystem renderSystem, D3D12RenderDevice device, D3D12DescriptorAllocator descriptorAllocator, D3D12ResourceDatabase resourceDatabase)
{
var desc = new AllocatorDesc
var desc = new D3D12MA_ALLOCATOR_DESC
{
pAdapter = (IDXGIAdapter*)device.Adapter,
pDevice = (ID3D12Device*)device.NativeDevice,
Flags = AllocatorFlags.DefaultPoolsNotZeroed | AllocatorFlags.MSAATexturesAlwaysCommitted
Flags = D3D12MA_ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA_ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED,
};
CreateAllocator(in desc, out _allocator);
D3D12MA_CreateAllocator(&desc, _allocator.GetAddressOf());
_device = device.NativeDevice;
_device = device;
_renderSystem = renderSystem;
_descriptorAllocator = descriptorAllocator;
_resourceDatabase = resourceDatabase;
@@ -78,9 +80,9 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Handle<GPUResource> TrackResource(ref readonly Allocation allocation, ResourceStates state, D3D12ResourceDescriptor resourceDescriptor, ResourceDesc desc, bool isTemp)
private Handle<GPUResource> TrackResource(ComPtr<D3D12MA_Allocation> allocation, D3D12_RESOURCE_STATES state, ResourceViewGroup resourceDescriptor, ResourceDesc desc, bool isTemp)
{
var handle = _resourceDatabase.AddResource(in allocation, _renderSystem.CPUFenceValue, D3D12StatesToRHIState(state), resourceDescriptor, desc);
var handle = _resourceDatabase.AddResource(allocation, _renderSystem.CPUFenceValue, D3D12StatesToRHIState(state), resourceDescriptor, desc);
if (isTemp)
{
@@ -90,58 +92,266 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
return handle;
}
private void CreateSRV(ID3D12Resource* pResource, CpuDescriptorHandle descriptorHandle, Format format, TextureDimension dimension, uint mipLevels, uint arraySize)
private D3D12_SHADER_RESOURCE_VIEW_DESC CreateSrvDesc(ID3D12Resource* pResource, bool isCubeMap, uint mipLevels, uint arraySize)
{
var srvDesc = new ShaderResourceViewDescription
var resourceDesc = pResource->GetDesc();
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
{
Format = format,
Format = resourceDesc.Format,
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
};
switch (dimension)
switch (resourceDesc.Dimension)
{
case TextureDimension.Texture2D:
srvDesc.ViewDimension = SrvDimension.Texture2D;
srvDesc.Texture2D = new Texture2DSrv
case D3D12_RESOURCE_DIMENSION_BUFFER:
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Buffer = new D3D12_BUFFER_SRV
{
MipLevels = mipLevels,
FirstElement = 0,
NumElements = (uint)(resourceDesc.Width / 4),
StructureByteStride = 0,
Flags = D3D12_BUFFER_SRV_FLAG_RAW,
};
break;
case TextureDimension.Texture3D:
srvDesc.ViewDimension = SrvDimension.Texture3D;
srvDesc.Texture3D = new Texture3DSrv
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
if (resourceDesc.DepthOrArraySize > 1)
{
MipLevels = 0,
};
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
srvDesc.Texture1DArray = new D3D12_TEX1D_ARRAY_SRV
{
MipLevels = mipLevels,
ArraySize = arraySize,
};
}
else
{
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
srvDesc.Texture1D = new D3D12_TEX1D_SRV
{
MipLevels = mipLevels,
};
}
break;
case TextureDimension.Texture2DArray:
srvDesc.ViewDimension = SrvDimension.Texture2DArray;
srvDesc.Texture2DArray = new Texture2DArraySrv
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
if (resourceDesc.DepthOrArraySize > 1)
{
if (isCubeMap)
{
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
srvDesc.TextureCubeArray = new D3D12_TEXCUBE_ARRAY_SRV
{
MipLevels = mipLevels,
NumCubes = arraySize / 6,
};
}
else
{
srvDesc.ViewDimension = resourceDesc.SampleDesc.Count > 1 ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc.Texture2DArray = new D3D12_TEX2D_ARRAY_SRV
{
MipLevels = mipLevels,
ArraySize = arraySize,
};
}
}
else
{
if (isCubeMap)
{
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
srvDesc.TextureCube = new D3D12_TEXCUBE_SRV
{
MipLevels = mipLevels,
};
}
else
{
srvDesc.ViewDimension = resourceDesc.SampleDesc.Count > 1 ? D3D12_SRV_DIMENSION_TEXTURE2DMS : D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D = new D3D12_TEX2D_SRV
{
MipLevels = mipLevels,
};
}
}
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
srvDesc.Texture3D = new D3D12_TEX3D_SRV
{
MipLevels = mipLevels,
ArraySize = arraySize,
};
break;
case TextureDimension.TextureCube:
srvDesc.ViewDimension = SrvDimension.TextureCube;
srvDesc.TextureCube = new TexureCubeSrv
{
MipLevels = mipLevels,
};
break;
case TextureDimension.TextureCubeArray:
srvDesc.ViewDimension = SrvDimension.TextureCubeArray;
srvDesc.TextureCubeArray = new TexureCubeArraySrv
{
MipLevels = mipLevels,
NumCubes = arraySize / 6,
};
break;
default:
throw new ArgumentException($"Unsupported texture dimension for SRV: {dimension}");
throw new ArgumentException($"Unsupported texture dimension for SRV: {resourceDesc.Dimension}");
}
_device->CreateShaderResourceView(pResource, &srvDesc, descriptorHandle);
return srvDesc;
}
private D3D12_RENDER_TARGET_VIEW_DESC CreateRtvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, uint planeSlice = 0)
{
var resourceDesc = pResource->GetDesc();
var rtvDesc = new D3D12_RENDER_TARGET_VIEW_DESC();
switch (resourceDesc.Dimension)
{
case D3D12_RESOURCE_DIMENSION_BUFFER:
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_BUFFER;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
rtvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_RTV_DIMENSION_TEXTURE1DARRAY : D3D12_RTV_DIMENSION_TEXTURE1D;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
if (resourceDesc.SampleDesc.Count > 1)
{
rtvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DMS;
}
else
{
rtvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DARRAY : D3D12_RTV_DIMENSION_TEXTURE2D;
}
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
break;
default:
throw new ArgumentException($"Unsupported texture dimension for SRV: {resourceDesc.Dimension}");
}
rtvDesc.Format = resourceDesc.Format;
var isArray =
rtvDesc.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DARRAY ||
rtvDesc.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
var arraySize = 1u;
if (isArray)
{
arraySize = resourceDesc.ArraySize() - firstArraySlice;
}
switch (rtvDesc.ViewDimension)
{
case D3D12_RTV_DIMENSION_BUFFER:
rtvDesc.Buffer.FirstElement = firstArraySlice;
rtvDesc.Buffer.NumElements = arraySize;
break;
case D3D12_RTV_DIMENSION_TEXTURE1D:
rtvDesc.Texture1D.MipSlice = mipSlice;
break;
case D3D12_RTV_DIMENSION_TEXTURE1DARRAY:
rtvDesc.Texture1DArray.MipSlice = mipSlice;
rtvDesc.Texture1DArray.FirstArraySlice = firstArraySlice;
rtvDesc.Texture1DArray.ArraySize = arraySize;
break;
case D3D12_RTV_DIMENSION_TEXTURE2D:
rtvDesc.Texture2D.MipSlice = mipSlice;
rtvDesc.Texture2D.PlaneSlice = planeSlice;
break;
case D3D12_RTV_DIMENSION_TEXTURE2DARRAY:
rtvDesc.Texture2DArray.MipSlice = mipSlice;
rtvDesc.Texture2DArray.FirstArraySlice = firstArraySlice;
rtvDesc.Texture2DArray.ArraySize = arraySize;
rtvDesc.Texture2DArray.PlaneSlice = planeSlice;
break;
case D3D12_RTV_DIMENSION_TEXTURE2DMS:
break;
case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY:
rtvDesc.Texture2DMSArray.FirstArraySlice = firstArraySlice;
rtvDesc.Texture2DMSArray.ArraySize = arraySize;
break;
case D3D12_RTV_DIMENSION_TEXTURE3D:
rtvDesc.Texture3D.MipSlice = mipSlice;
rtvDesc.Texture3D.FirstWSlice = firstArraySlice;
rtvDesc.Texture3D.WSize = arraySize;
break;
default:
throw new ArgumentException($"Unsupported RTV dimension: {rtvDesc.ViewDimension}");
}
return rtvDesc;
}
private D3D12_DEPTH_STENCIL_VIEW_DESC CreateDsvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, D3D12_DSV_FLAGS flags = D3D12_DSV_FLAG_NONE)
{
var resourceDesc = pResource->GetDesc();
var dsvDesc = new D3D12_DEPTH_STENCIL_VIEW_DESC
{
Flags = flags,
};
switch (resourceDesc.Dimension)
{
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
dsvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_DSV_DIMENSION_TEXTURE1DARRAY : D3D12_DSV_DIMENSION_TEXTURE1D;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
if (resourceDesc.SampleDesc.Count > 1)
{
dsvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DMS;
}
else
{
dsvDesc.ViewDimension = resourceDesc.DepthOrArraySize > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DARRAY : D3D12_DSV_DIMENSION_TEXTURE2D;
}
break;
}
dsvDesc.Format = resourceDesc.Format;
var isArray =
dsvDesc.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DARRAY ||
dsvDesc.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
var arraySize = 1u;
if (isArray)
{
arraySize = resourceDesc.ArraySize() - firstArraySlice;
}
switch (dsvDesc.ViewDimension)
{
case D3D12_DSV_DIMENSION_TEXTURE1D:
dsvDesc.Texture1D.MipSlice = mipSlice;
break;
case D3D12_DSV_DIMENSION_TEXTURE1DARRAY:
dsvDesc.Texture1DArray.MipSlice = mipSlice;
dsvDesc.Texture1DArray.FirstArraySlice = firstArraySlice;
dsvDesc.Texture1DArray.ArraySize = arraySize;
break;
case D3D12_DSV_DIMENSION_TEXTURE2D:
dsvDesc.Texture2D.MipSlice = mipSlice;
break;
case D3D12_DSV_DIMENSION_TEXTURE2DARRAY:
dsvDesc.Texture2DArray.MipSlice = mipSlice;
dsvDesc.Texture2DArray.FirstArraySlice = firstArraySlice;
dsvDesc.Texture2DArray.ArraySize = arraySize;
break;
case D3D12_DSV_DIMENSION_TEXTURE2DMS:
break;
case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY:
dsvDesc.Texture2DMSArray.FirstArraySlice = firstArraySlice;
dsvDesc.Texture2DMSArray.ArraySize = arraySize;
break;
default:
break;
}
return dsvDesc;
}
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
@@ -154,33 +364,33 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
var resourceFlags = ConvertTextureUsage(desc.Usage);
var resourceDesc = desc.Dimension switch
{
TextureDimension.Texture2D => ResourceDescription.Tex2D(
TextureDimension.Texture2D => D3D12_RESOURCE_DESC.Tex2D(
d3d12Format,
desc.Width,
desc.Height,
mipLevels: mipLevels,
flags: resourceFlags),
TextureDimension.Texture3D => ResourceDescription.Tex3D(
TextureDimension.Texture3D => D3D12_RESOURCE_DESC.Tex3D(
d3d12Format,
desc.Width,
desc.Height,
(ushort)desc.Slice,
flags: resourceFlags),
TextureDimension.TextureCube => ResourceDescription.Tex2D(
TextureDimension.TextureCube => D3D12_RESOURCE_DESC.Tex2D(
d3d12Format,
desc.Width,
desc.Height,
mipLevels: mipLevels,
arraySize: 6,
flags: resourceFlags),
TextureDimension.Texture2DArray => ResourceDescription.Tex2D(
TextureDimension.Texture2DArray => D3D12_RESOURCE_DESC.Tex2D(
d3d12Format,
desc.Width,
desc.Height,
mipLevels: mipLevels,
arraySize: (ushort)desc.Slice,
flags: resourceFlags),
TextureDimension.TextureCubeArray => ResourceDescription.Tex2D(
TextureDimension.TextureCubeArray => D3D12_RESOURCE_DESC.Tex2D(
d3d12Format,
desc.Width,
desc.Height,
@@ -190,57 +400,64 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
_ => throw new ArgumentException($"Unsupported texture dimension: {desc.Dimension}"),
};
var allocationDesc = new AllocationDesc
var allocationDesc = new D3D12MA_ALLOCATION_DESC
{
HeapType = HeapType.Default,
Flags = AllocationFlags.None
HeapType = D3D12_HEAP_TYPE_DEFAULT,
Flags = D3D12MA_ALLOCATION_FLAG_NONE
};
var initialState = DetermineInitialTextureState(desc.Usage);
Allocation allocation = default;
ThrowIfFailed(_allocator.CreateResource(&allocationDesc, in resourceDesc, initialState, null, &allocation, IID_NULL, null));
ComPtr<D3D12MA_Allocation> allocation = default;
ThrowIfFailed(_allocator.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, allocation.GetAddressOf(), IID_NULL, null));
var resourceDescriptor = D3D12ResourceDescriptor.Invalid;
var resourceDescriptor = ResourceViewGroup.Invalid;
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
{
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv);
CreateSRV(allocation.Resource, cpuHandle, d3d12Format, desc.Dimension, mipLevels, desc.Slice);
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
var srvDesc = CreateSrvDesc(allocation.Get()->GetResource(), isCubeMap, mipLevels, desc.Slice);
_device.NativeDevice->CreateShaderResourceView(allocation.Get()->GetResource(), &srvDesc, cpuHandle);
}
if (desc.Usage.HasFlag(TextureUsage.RenderTarget))
{
resourceDescriptor.rtv = _descriptorAllocator.AllocateRTV(isTemp);
var rtvDesc = new RenderTargetViewDescription(allocation.Resource);
_device->CreateRenderTargetView(allocation.Resource, &rtvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.rtv));
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.rtv);
var rtvDesc = CreateRtvDesc(allocation.Get()->GetResource());
_device.NativeDevice->CreateRenderTargetView(allocation.Get()->GetResource(), &rtvDesc, cpuHandle);
}
if (desc.Usage.HasFlag(TextureUsage.DepthStencil))
{
resourceDescriptor.dsv = _descriptorAllocator.AllocateDSV(isTemp);
var dsvDesc = new DepthStencilViewDescription(allocation.Resource);
_device->CreateDepthStencilView(allocation.Resource, &dsvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv));
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv);
var dsvDesc = CreateDsvDesc(allocation.Get()->GetResource());
_device.NativeDevice->CreateDepthStencilView(allocation.Get()->GetResource(), &dsvDesc, cpuHandle);
}
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
{
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
var uavDesc = new UnorderedAccessViewDescription
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
{
ViewDimension = UavDimension.Texture2D,
ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D,
Format = d3d12Format,
Texture2D = new Texture2DUav
Texture2D = new D3D12_TEX2D_UAV
{
MipSlice = 0,
PlaneSlice = 0,
}
};
_device->CreateUnorderedAccessView(allocation.Resource, null, &uavDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav));
_device.NativeDevice->CreateUnorderedAccessView(allocation.Get()->GetResource(), null, &uavDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav));
}
var handle = TrackResource(ref allocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
var handle = TrackResource(allocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
return handle.AsTexture();
}
@@ -253,56 +470,56 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
{
CheckBufferSize((uint)desc.Size);
CheckBufferSize(desc.Size);
var resourceDescription = ResourceDescription.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
var allocationDesc = new AllocationDesc
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
var allocationDesc = new D3D12MA_ALLOCATION_DESC
{
HeapType = ConvertMemoryType(desc.MemoryType),
Flags = AllocationFlags.None
Flags = D3D12MA_ALLOCATION_FLAG_NONE
};
var initialState = DetermineInitialBufferState(desc.Usage, desc.MemoryType);
Allocation allocation = default;
ThrowIfFailed(_allocator.CreateResource(&allocationDesc, in resourceDescription, initialState, null, &allocation, IID_NULL, null));
ComPtr<D3D12MA_Allocation> allocation = default;
ThrowIfFailed(_allocator.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, allocation.GetAddressOf(), IID_NULL, null));
var resourceDescriptor = D3D12ResourceDescriptor.Invalid;
if (desc.Usage.HasFlag(BufferUsage.ShaderResource) && desc.CreationFlags.HasFlag(BufferCreationFlags.Bindless))
var resourceDescriptor = ResourceViewGroup.Invalid;
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
{
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
var srvDesc = new ShaderResourceViewDescription
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
{
ViewDimension = SrvDimension.Buffer,
ViewDimension = D3D12_SRV_DIMENSION_BUFFER,
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
};
if (desc.Usage.HasFlag(BufferUsage.Raw))
{
srvDesc.Format = Format.R32Typeless;
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = (uint)(desc.Size / 4);
srvDesc.Buffer.NumElements = desc.Size / 4;
srvDesc.Buffer.StructureByteStride = 0;
srvDesc.Buffer.Flags = BufferSrvFlags.Raw;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
}
else
{
srvDesc.Format = Format.Unknown;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = (uint)(desc.Size / desc.Stride);
srvDesc.Buffer.NumElements = desc.Size / desc.Stride;
srvDesc.Buffer.StructureByteStride = desc.Stride;
srvDesc.Buffer.Flags = BufferSrvFlags.None;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
}
_device->CreateShaderResourceView(allocation.Resource, &srvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv));
_device.NativeDevice->CreateShaderResourceView(allocation.Get()->GetResource(), &srvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv));
}
var handle = TrackResource(ref allocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
var handle = TrackResource(allocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
return handle.AsGraphicsBuffer();
}
public Handle<GraphicsBuffer> CreateUploadBuffer(ulong size, bool isTemp = true)
public Handle<GraphicsBuffer> CreateUploadBuffer(uint size, bool isTemp = true)
{
var desc = new BufferDesc
{
@@ -318,20 +535,18 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
{
var vertexBufferDesc = new BufferDesc
{
Size = (ulong)(vertices.Count * Unsafe.SizeOf<Vertex>()),
Size = (uint)(vertices.Count * Unsafe.SizeOf<Vertex>()),
Stride = (uint)Unsafe.SizeOf<Vertex>(),
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource,
MemoryType = MemoryType.Default,
CreationFlags = BufferCreationFlags.Bindless
};
var indexBufferDesc = new BufferDesc
{
Size = (ulong)(indices.Count * sizeof(uint)),
Size = (uint)(indices.Count * sizeof(uint)),
Stride = sizeof(uint),
Usage = BufferUsage.Index | BufferUsage.ShaderResource,
MemoryType = MemoryType.Default,
CreationFlags = BufferCreationFlags.Bindless
};
var vertexBuffer = CreateBuffer(ref vertexBufferDesc);
@@ -357,30 +572,20 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
ref var shaderRef = ref _resourceDatabase.GetShaderReference(shader);
if (shaderRef.ConstantBuffers.Count > 0)
var desc = new BufferDesc
{
var maxSlot = shaderRef.ConstantBuffers.Max(cb => cb.RegisterSlot);
materialData._cBufferCaches = new UnsafeArray<CBufferCache>((int)maxSlot + 1, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
Size = shaderRef.PerMaterialBufferInfo.Size,
Usage = BufferUsage.Constant,
MemoryType = MemoryType.Default,
};
foreach (var cbufferInfo in shaderRef.ConstantBuffers)
{
var desc = new BufferDesc
{
Size = cbufferInfo.Size,
Usage = BufferUsage.Constant,
MemoryType = MemoryType.Default,
};
var buffer = CreateBuffer(ref desc);
materialData._cBufferCaches[cbufferInfo.RegisterSlot] = new CBufferCache(buffer, cbufferInfo.Size);
}
}
var buffer = CreateBuffer(ref desc);
materialData._materialPropertiesCache = new CBufferCache(buffer, shaderRef.PerMaterialBufferInfo.Size);
return _resourceDatabase.AddMaterial(ref materialData);
}
public Identifier<Shader> CreateShader()
public Identifier<Shader> CreateShader(ShaderDescriptor descriptor)
{
var shaderData = new Shader();
return _resourceDatabase.AddShader(ref shaderData);
@@ -388,149 +593,136 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
#region Conversion Methods
private static Format ConvertTextureFormat(TextureFormat format)
private static DXGI_FORMAT ConvertTextureFormat(TextureFormat format)
{
return format switch
{
TextureFormat.R8G8B8A8_UNorm => Format.R8G8B8A8Unorm,
TextureFormat.B8G8R8A8_UNorm => Format.B8G8R8A8Unorm,
TextureFormat.R16G16B16A16_Float => Format.R16G16B16A16Float,
TextureFormat.R32G32B32A32_Float => Format.R32G32B32A32Float,
TextureFormat.D24_UNorm_S8_UInt => Format.D24UnormS8Uint,
TextureFormat.D32_Float => Format.D32Float,
TextureFormat.R8G8B8A8_UNorm => DXGI_FORMAT_R8G8B8A8_UNORM,
TextureFormat.B8G8R8A8_UNorm => DXGI_FORMAT_B8G8R8A8_UNORM,
TextureFormat.R16G16B16A16_Float => DXGI_FORMAT_R16G16B16A16_FLOAT,
TextureFormat.R32G32B32A32_Float => DXGI_FORMAT_R32G32B32A32_FLOAT,
TextureFormat.D24_UNorm_S8_UInt => DXGI_FORMAT_D24_UNORM_S8_UINT,
TextureFormat.D32_Float => DXGI_FORMAT_D32_FLOAT,
_ => throw new ArgumentException($"Unsupported texture format: {format}")
};
}
private static ResourceFlags ConvertTextureUsage(TextureUsage usage)
private static D3D12_RESOURCE_FLAGS ConvertTextureUsage(TextureUsage usage)
{
var flags = ResourceFlags.None;
var flags = D3D12_RESOURCE_FLAG_NONE;
if (usage.HasFlag(TextureUsage.RenderTarget))
{
flags |= ResourceFlags.AllowRenderTarget;
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}
if (usage.HasFlag(TextureUsage.DepthStencil))
{
flags |= ResourceFlags.AllowDepthStencil;
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
}
if (usage.HasFlag(TextureUsage.UnorderedAccess))
{
flags |= ResourceFlags.AllowUnorderedAccess;
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
return flags;
}
private static ResourceFlags ConvertBufferUsage(BufferUsage usage)
private static D3D12_RESOURCE_FLAGS ConvertBufferUsage(BufferUsage usage)
{
var flags = ResourceFlags.None;
var flags = D3D12_RESOURCE_FLAG_NONE;
if (usage.HasFlag(BufferUsage.Raw))
{
flags |= ResourceFlags.AllowUnorderedAccess;
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
return flags;
}
private static HeapType ConvertMemoryType(MemoryType memoryType)
private static D3D12_HEAP_TYPE ConvertMemoryType(MemoryType memoryType)
{
return memoryType switch
{
MemoryType.Default => HeapType.Default,
MemoryType.Upload => HeapType.Upload,
MemoryType.Readback => HeapType.Readback,
MemoryType.Default => D3D12_HEAP_TYPE_DEFAULT,
MemoryType.Upload => D3D12_HEAP_TYPE_UPLOAD,
MemoryType.Readback => D3D12_HEAP_TYPE_READBACK,
_ => throw new ArgumentException($"Unsupported memory type: {memoryType}")
};
}
private static ResourceStates DetermineInitialTextureState(TextureUsage usage)
private static D3D12_RESOURCE_STATES DetermineInitialTextureState(TextureUsage usage)
{
if (usage.HasFlag(TextureUsage.RenderTarget))
{
return ResourceStates.RenderTarget;
return D3D12_RESOURCE_STATE_RENDER_TARGET;
}
if (usage.HasFlag(TextureUsage.DepthStencil))
{
return ResourceStates.DepthWrite;
return D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
if (usage.HasFlag(TextureUsage.UnorderedAccess))
{
return ResourceStates.UnorderedAccess;
return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
return ResourceStates.Common;
return D3D12_RESOURCE_STATE_COMMON;
}
private static ResourceStates DetermineInitialBufferState(BufferUsage usage, MemoryType memoryType)
private static D3D12_RESOURCE_STATES DetermineInitialBufferState(BufferUsage usage, MemoryType memoryType)
{
if (memoryType == MemoryType.Upload)
{
return ResourceStates.GenericRead;
return D3D12_RESOURCE_STATE_GENERIC_READ;
}
if (memoryType == MemoryType.Readback)
{
return ResourceStates.CopyDest;
return D3D12_RESOURCE_STATE_COPY_DEST;
}
if (usage.HasFlag(BufferUsage.Vertex))
{
return ResourceStates.VertexAndConstantBuffer;
return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
if (usage.HasFlag(BufferUsage.Index))
{
return ResourceStates.IndexBuffer;
return D3D12_RESOURCE_STATE_INDEX_BUFFER;
}
if (usage.HasFlag(BufferUsage.Constant))
{
return ResourceStates.VertexAndConstantBuffer;
return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
return ResourceStates.Common;
return D3D12_RESOURCE_STATE_COMMON;
}
private static ResourceState D3D12StatesToRHIState(ResourceStates states)
private static ResourceState D3D12StatesToRHIState(D3D12_RESOURCE_STATES states)
{
switch (states)
return states switch
{
//case ResourceStates.None:
//case ResourceStates.Present:
case ResourceStates.Common:
return ResourceState.Common;
case ResourceStates.VertexAndConstantBuffer:
return ResourceState.VertexAndConstantBuffer;
case ResourceStates.IndexBuffer:
return ResourceState.IndexBuffer;
case ResourceStates.RenderTarget:
return ResourceState.RenderTarget;
case ResourceStates.UnorderedAccess:
return ResourceState.UnorderedAccess;
case ResourceStates.DepthWrite:
return ResourceState.DepthWrite;
case ResourceStates.DepthRead:
return ResourceState.DepthRead;
case ResourceStates.PixelShaderResource:
return ResourceState.PixelShaderResource;
D3D12_RESOURCE_STATE_COMMON => ResourceState.Common,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER => ResourceState.VertexAndConstantBuffer,
D3D12_RESOURCE_STATE_INDEX_BUFFER => ResourceState.IndexBuffer,
D3D12_RESOURCE_STATE_RENDER_TARGET => ResourceState.RenderTarget,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS => ResourceState.UnorderedAccess,
D3D12_RESOURCE_STATE_DEPTH_WRITE => ResourceState.DepthWrite,
D3D12_RESOURCE_STATE_DEPTH_READ => ResourceState.DepthRead,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE => ResourceState.PixelShaderResource,
//case ResourceStates.Predication:
case ResourceStates.IndirectArgument:
return ResourceState.IndirectArgument;
case ResourceStates.CopyDest:
return ResourceState.CopyDest;
case ResourceStates.CopySource:
return ResourceState.CopySource;
case ResourceStates.GenericRead:
return ResourceState.GenericRead;
default:
return ResourceState.Common;
}
D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT => ResourceState.IndirectArgument,
D3D12_RESOURCE_STATE_COPY_DEST => ResourceState.CopyDest,
D3D12_RESOURCE_STATE_COPY_SOURCE => ResourceState.CopySource,
D3D12_RESOURCE_STATE_GENERIC_READ => ResourceState.GenericRead,
_ => ResourceState.Common,
};
}
#endregion
@@ -580,7 +772,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
}
_temResources.Dispose();
_allocator.Release();
_allocator.Dispose();
GC.SuppressFinalize(this);
}

View File

@@ -1,12 +1,12 @@
using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.Data;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.Collections;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.InteropServices;
using Win32;
using Win32.Graphics.D3D12MemoryAllocator;
using Win32.Graphics.Direct3D12;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Ghost.Graphics.D3D12;
@@ -15,42 +15,38 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
internal unsafe struct ResourceInfo
{
[StructLayout(LayoutKind.Explicit)]
private struct ResourceUnion
public struct ResourceUnion
{
[FieldOffset(0)]
public Allocation allocation;
public ComPtr<D3D12MA_Allocation> allocation;
[FieldOffset(0)]
public ComPtr<ID3D12Resource> resource;
public ResourceUnion(Allocation allocation)
public ResourceUnion(ComPtr<D3D12MA_Allocation> allocation)
{
this.allocation = allocation;
this.resource = default;
}
public ResourceUnion(ComPtr<ID3D12Resource> resource)
{
this.resource = resource;
this.allocation = default;
}
}
private ResourceUnion _resourceUnion;
private readonly bool _isExternal;
public D3D12ResourceDescriptor descriptor;
public ResourceDesc desc;
public ResourceViewGroup descriptor;
public ResourceUnion resourceUnion;
public uint cpuFenceValue;
public ResourceState state;
public ResourceDesc desc;
public readonly bool isExternal;
public readonly bool Allocated => _isExternal ? _resourceUnion.resource.Get() != null : _resourceUnion.allocation.IsNotNull;
public readonly ID3D12Resource* ResourcePtr => _isExternal ? _resourceUnion.resource.Get() : _resourceUnion.allocation.Resource;
public readonly bool Allocated => isExternal ? resourceUnion.resource.Get() != null : resourceUnion.allocation.Get()->IsNotNull;
public readonly ID3D12Resource* ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
public ResourceInfo(in Allocation allocation, uint cpuFenceValue, ResourceState state, D3D12ResourceDescriptor resourceDescriptor, ResourceDesc desc)
public ResourceInfo(ComPtr<D3D12MA_Allocation> allocation, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
{
this._resourceUnion = new ResourceUnion(allocation);
this._isExternal = false;
this.resourceUnion = new ResourceUnion(allocation);
this.isExternal = false;
this.descriptor = resourceDescriptor;
this.cpuFenceValue = cpuFenceValue;
@@ -60,8 +56,8 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
public ResourceInfo(ComPtr<ID3D12Resource> resource, ResourceState state)
{
this._resourceUnion = new ResourceUnion(resource);
this._isExternal = true;
this.resourceUnion = new ResourceUnion(resource);
this.isExternal = true;
this.descriptor = default;
this.cpuFenceValue = ~0u;
@@ -74,16 +70,16 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
var refCount = 0u;
if (Allocated)
{
if (_isExternal)
if (isExternal)
{
refCount = _resourceUnion.resource.Get()->Release();
refCount = resourceUnion.resource.Get()->Release();
}
else
{
refCount = _resourceUnion.allocation.Release();
refCount = resourceUnion.allocation.Get()->Release();
}
_resourceUnion = default;
resourceUnion = default;
descriptor = default;
}
@@ -131,7 +127,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
Dispose();
}
public unsafe Handle<GPUResource> ImportExternalResource<T>(T resource, ResourceState initialState)
public Handle<GPUResource> ImportExternalResource<T>(T resource, ResourceState initialState)
where T : unmanaged
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -145,7 +141,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
return new Handle<GPUResource>(id, generation);
}
public Handle<GPUResource> AddResource(ref readonly Allocation allocation, uint cpuFenceValue, ResourceState initialState, D3D12ResourceDescriptor resourceDescriptor, ResourceDesc desc)
public Handle<GPUResource> AddResource(ComPtr<D3D12MA_Allocation> allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
{
ObjectDisposedException.ThrowIf(_disposed, this);

View File

@@ -1,10 +1,12 @@
#undef SUPPORT_TEXTURE_BINDING
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.Data;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Win32;
using Win32.Graphics.Direct3D;
using Win32.Graphics.Direct3D.Dxc;
using Win32.Graphics.Direct3D12;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Ghost.Graphics.D3D12;
@@ -71,8 +73,11 @@ internal unsafe static class D3D12ShaderCompiler
using ComPtr<IDxcIncludeHandler> includeHandler = default;
// Create DXC compiler and utils
DxcCreateInstance(in CLSID_DxcCompiler, __uuidof<IDxcCompiler3>(), compiler.GetVoidAddressOf());
DxcCreateInstance(in CLSID_DxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf());
var pDxcCompiler = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcCompiler);
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
DxcCreateInstance(pDxcCompiler, __uuidof<IDxcCompiler3>(), compiler.GetVoidAddressOf());
DxcCreateInstance(pDxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf());
utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf());
// Create source blob
@@ -116,16 +121,16 @@ internal unsafe static class D3D12ShaderCompiler
{
Ptr = sourceBlob.Get()->GetBufferPointer(),
Size = sourceBlob.Get()->GetBufferSize(),
Encoding = DXC_CP_UTF8
Encoding = DXC.DXC_CP_UTF8
};
compiler.Get()->Compile(&buffer, (char**)argsPtr, (uint)argsArray.Length, includeHandler.Get(), __uuidof<IDxcResult>(), result.GetVoidAddressOf());
}
// Check compilation result
HResult hrStatus;
HRESULT hrStatus;
result.Get()->GetStatus(&hrStatus);
if (hrStatus.Failure)
if (hrStatus.FAILED)
{
// Get error messages
using ComPtr<IDxcBlobEncoding> errorBlob = default;
@@ -153,7 +158,7 @@ internal unsafe static class D3D12ShaderCompiler
// Get reflection data using DXC API
using ComPtr<IDxcBlob> reflectionBlob = default;
result.Get()->GetOutput(DxcOutKind.Reflection, __uuidof<IDxcBlob>(), reflectionBlob.GetVoidAddressOf(), null);
result.Get()->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof<IDxcBlob>(), reflectionBlob.GetVoidAddressOf(), null);
if (reflectionBlob.Get() == null)
{
@@ -188,18 +193,20 @@ internal unsafe static class D3D12ShaderCompiler
shader.PropertyNameToIdMap[name] = id;
}
// TODO: Since we are using fixed root signature layout, the reflection pass should only validate the layout, not generate it.
public static void PerformDXCReflection(ref Shader shader, IDxcBlob* reflectionBlob)
{
// Create DXC utils to parse reflection data
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
using ComPtr<IDxcUtils> utils = default;
DxcCreateInstance(CLSID_DxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf());
DxcCreateInstance(pDxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf());
// Create reflection interface from blob
var reflectionData = new DxcBuffer
{
Ptr = reflectionBlob->GetBufferPointer(),
Size = reflectionBlob->GetBufferSize(),
Encoding = DXC_CP_ACP
Encoding = DXC.DXC_CP_ACP
};
using ComPtr<ID3D12ShaderReflection> reflection = default;
@@ -210,7 +217,7 @@ internal unsafe static class D3D12ShaderCompiler
throw new Exception("Failed to create shader reflection from DXC output");
}
ShaderDescription shaderDesc;
D3D12_SHADER_DESC shaderDesc;
reflection.Get()->GetDesc(&shaderDesc);
var cbufferRegistry = new Dictionary<string, CBufferInfo>();
@@ -218,12 +225,12 @@ internal unsafe static class D3D12ShaderCompiler
for (uint i = 0; i < shaderDesc.BoundResources; i++)
{
ShaderInputBindDescription bindDesc;
D3D12_SHADER_INPUT_BIND_DESC bindDesc;
reflection.Get()->GetResourceBindingDesc(i, &bindDesc);
switch (bindDesc.Type)
{
case ShaderInputType.ConstantBuffer:
case D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER:
{
var cbufferName = Marshal.PtrToStringAnsi((IntPtr)bindDesc.Name);
if (cbufferName == null || cbufferRegistry.ContainsKey(cbufferName))
@@ -232,7 +239,7 @@ internal unsafe static class D3D12ShaderCompiler
}
var cbuffer = reflection.Get()->GetConstantBufferByName(bindDesc.Name);
ShaderBufferDescription cbufferDesc;
D3D12_SHADER_BUFFER_DESC cbufferDesc;
cbuffer->GetDesc(&cbufferDesc);
var cbufferInfo = new CBufferInfo
@@ -245,7 +252,7 @@ internal unsafe static class D3D12ShaderCompiler
for (uint j = 0; j < cbufferDesc.Variables; j++)
{
var variable = cbuffer->GetVariableByIndex(j);
ShaderVariableDescription varDesc;
D3D12_SHADER_VARIABLE_DESC varDesc;
variable->GetDesc(&varDesc);
var variableName = Marshal.PtrToStringAnsi((IntPtr)varDesc.Name);
@@ -267,8 +274,9 @@ internal unsafe static class D3D12ShaderCompiler
break;
}
case ShaderInputType.Texture:
case D3D_SHADER_INPUT_TYPE.D3D_SIT_TEXTURE:
{
#if SUPPORT_TEXTURE_BINDING
var textureName = Marshal.PtrToStringAnsi((IntPtr)bindDesc.Name);
if (textureName == null || textureRegistry.ContainsKey(textureName))
{
@@ -285,20 +293,16 @@ internal unsafe static class D3D12ShaderCompiler
textureRegistry.Add(textureName, textureInfo);
break;
#endif
throw new NotSupportedException("Texture bindings are not supported in current version. Please use bindless textures.");
}
}
}
shader.ConstantBuffers.Clear();
shader.PerMaterialBufferInfo.Clear();
foreach (var cbuf in cbufferRegistry.Values)
{
shader.ConstantBuffers.Add(cbuf);
}
shader.RegularTextures.Clear();
foreach (var tex in textureRegistry.Values)
{
shader.RegularTextures.Add(tex);
shader.PerMaterialBufferInfo.Add(cbuf);
}
}
}

View File

@@ -6,10 +6,10 @@ using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.CompilerServices;
using Win32;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi;
using Win32.Graphics.Dxgi.Common;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12;
@@ -55,18 +55,18 @@ internal unsafe class D3D12SwapChain : ISwapChain
private void CreateSwapChain(IDXGIFactory7* pFactory, ID3D12CommandQueue* commandQueue, SwapChainDesc desc)
{
var swapChainDesc = new SwapChainDescription1
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
{
Width = desc.width,
Height = desc.height,
Format = ConvertTextureFormat(desc.format),
SampleDesc = new SampleDescription(1, 0),
BufferUsage = Usage.BackBuffer | Usage.RenderTargetOutput,
Format = desc.format.ToD3D12Format(),
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT,
Scaling = Scaling.Stretch,
SwapEffect = SwapEffect.FlipDiscard,
AlphaMode = AlphaMode.Ignore,
Flags = SwapChainFlags.AllowTearing,
Scaling = DXGI_SCALING_STRETCH,
SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
AlphaMode = DXGI_ALPHA_MODE_IGNORE,
Flags = (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING,
Stereo = false,
};
@@ -86,14 +86,14 @@ internal unsafe class D3D12SwapChain : ISwapChain
break;
case SwapChainTargetType.WindowHandle:
var swapChainFullscreenDesc = new SwapChainFullscreenDescription
var swapChainFullscreenDesc = new DXGI_SWAP_CHAIN_FULLSCREEN_DESC
{
Windowed = true,
};
pFactory->CreateSwapChainForHwnd(
(IUnknown*)commandQueue,
desc.target.windowHandle,
new HWND(desc.target.windowHandle.ToPointer()),
&swapChainDesc,
&swapChainFullscreenDesc,
null,
@@ -104,7 +104,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
throw new ArgumentException("Unsupported swap chain target type.");
}
if (tempSwapChain.Get()->QueryInterface(__uuidof<IDXGISwapChain4>(), _swapChain.GetVoidAddressOf()).Failure)
if (tempSwapChain.Get()->QueryInterface(__uuidof<IDXGISwapChain4>(), _swapChain.GetVoidAddressOf()).FAILED)
{
throw new InvalidOperationException("Failed to create IDXGISwapChain4 interface.");
}
@@ -130,10 +130,10 @@ internal unsafe class D3D12SwapChain : ISwapChain
public void Present(bool vsync = true)
{
var presentFlags = PresentFlags.None;
var presentFlags = 0u;
var syncInterval = vsync ? 1u : 0u;
if (_swapChain.Get()->Present(syncInterval, presentFlags).Failure)
if (_swapChain.Get()->Present(syncInterval, presentFlags).FAILED)
{
throw new InvalidOperationException("Failed to present swap chain.");
}
@@ -153,7 +153,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
}
// Resize the swap chain
if (_swapChain.Get()->ResizeBuffers(BufferCount, width, height, Format.B8G8R8A8Unorm, SwapChainFlags.AllowTearing).Failure)
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.");
}
@@ -165,18 +165,6 @@ internal unsafe class D3D12SwapChain : ISwapChain
CreateBackBuffers();
}
private static Format ConvertTextureFormat(TextureFormat format)
{
return format switch
{
TextureFormat.R8G8B8A8_UNorm => Format.R8G8B8A8Unorm,
TextureFormat.B8G8R8A8_UNorm => Format.B8G8R8A8Unorm,
TextureFormat.R16G16B16A16_Float => Format.R16G16B16A16Float,
TextureFormat.R32G32B32A32_Float => Format.R32G32B32A32Float,
_ => throw new ArgumentException($"Unsupported texture format: {format}")
};
}
public void Dispose()
{
if (_disposed)

View File

@@ -7,7 +7,7 @@ internal readonly struct DSVDesc : IIdentifierType;
internal readonly struct CbvSrvUavDesc : IIdentifierType;
internal readonly struct SamplerDesc : IIdentifierType;
internal struct D3D12ResourceDescriptor
internal struct ResourceViewGroup
{
public Identifier<RTVDesc> rtv;
public Identifier<DSVDesc> dsv;
@@ -16,11 +16,13 @@ internal struct D3D12ResourceDescriptor
public Identifier<CbvSrvUavDesc> uav;
public Identifier<SamplerDesc> sampler;
public static D3D12ResourceDescriptor Invalid => new()
public static ResourceViewGroup Invalid => new()
{
rtv = Identifier<RTVDesc>.Invalid,
dsv = Identifier<DSVDesc>.Invalid,
srv = Identifier<CbvSrvUavDesc>.Invalid,
cbv = Identifier<CbvSrvUavDesc>.Invalid,
uav = Identifier<CbvSrvUavDesc>.Invalid,
sampler = Identifier<SamplerDesc>.Invalid,
};
}

View File

@@ -1,32 +1,34 @@
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Utilities;
using System.Diagnostics;
using System.Numerics;
using Win32;
using Win32.Graphics.Direct3D12;
using DescriptorIndex = System.Int32;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.D3D12_Alias;
namespace Ghost.Graphics.D3D12.Utilities;
internal unsafe struct D3D12DescriptorHeap : IDisposable
{
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = -1;
private const int _INVALID_DESCRIPTOR_INDEX = -1;
private readonly D3D12RenderDevice _device;
private ComPtr<ID3D12DescriptorHeap> _heap;
private ComPtr<ID3D12DescriptorHeap> _shaderVisibleHeap;
private CpuDescriptorHandle _startCpuHandle;
private CpuDescriptorHandle _startCpuHandleShaderVisible;
private GpuDescriptorHandle _startGpuHandleShaderVisible;
private DescriptorIndex _searchStart;
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandle;
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandleShaderVisible;
private D3D12_GPU_DESCRIPTOR_HANDLE _startGpuHandleShaderVisible;
private int _searchStart;
private UnsafeArray<bool> _allocatedDescriptors;
private readonly DescriptorIndex _dynamicHeapStart;
private DescriptorIndex _currentDynamicOffset;
private readonly int _dynamicHeapStart;
private int _currentDynamicOffset;
private readonly Lock _lock = new();
public DescriptorHeapType HeapType
public D3D12_DESCRIPTOR_HEAP_TYPE HeapType
{
get;
}
@@ -54,7 +56,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
public D3D12DescriptorHeap(string name, D3D12RenderDevice device, DescriptorHeapType type, int numDescriptors, int dynamicHeapStart)
public D3D12DescriptorHeap(string name, D3D12RenderDevice device, D3D12_DESCRIPTOR_HEAP_TYPE type, int numDescriptors, int dynamicHeapStart)
{
numDescriptors = Math.Max(64, numDescriptors);
@@ -62,7 +64,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
HeapType = type;
NumDescriptors = numDescriptors;
ShaderVisible = type == DescriptorHeapType.CbvSrvUav || type == DescriptorHeapType.Sampler;
ShaderVisible = type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
Stride = device.NativeDevice->GetDescriptorHandleIncrementSize(type);
_dynamicHeapStart = Math.Clamp(dynamicHeapStart, 0, numDescriptors);
@@ -71,16 +73,16 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
var success = AllocateResources(numDescriptors);
Debug.Assert(success);
_heap.Get()->SetName(name);
_heap.Get()->SetName(name.AsSpan().GetUnsafePtr());
if (ShaderVisible)
{
_shaderVisibleHeap.Get()->SetName($"{name} Shader Visible");
_shaderVisibleHeap.Get()->SetName($"{name} Shader Visible".AsSpan().GetUnsafePtr());
}
}
public DescriptorIndex AllocateDescriptor() => AllocateDescriptors(1);
public int AllocateDescriptor() => AllocateDescriptors(1);
public DescriptorIndex AllocateDescriptors(int count)
public int AllocateDescriptors(int count)
{
lock (_lock)
{
@@ -125,9 +127,9 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
}
}
public DescriptorIndex AllocateDescriptorDynamic() => AllocateDescriptorsDynamic(1);
public int AllocateDescriptorDynamic() => AllocateDescriptorsDynamic(1);
public DescriptorIndex AllocateDescriptorsDynamic(int count)
public int AllocateDescriptorsDynamic(int count)
{
if (count <= 0)
{
@@ -157,9 +159,9 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
}
}
public void ReleaseDescriptor(DescriptorIndex index) => ReleaseDescriptors(index, 1);
public void ReleaseDescriptor(int index) => ReleaseDescriptors(index, 1);
public void ReleaseDescriptors(DescriptorIndex baseIndex, int count = 1)
public void ReleaseDescriptors(int baseIndex, int count = 1)
{
if (count == 0)
{
@@ -203,7 +205,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
}
}
public readonly CpuDescriptorHandle GetCpuHandle(DescriptorIndex index)
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int index)
{
if (index < 0 || index >= NumDescriptors)
{
@@ -213,7 +215,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
return _startCpuHandle.Offset(index, Stride);
}
public readonly CpuDescriptorHandle GetCpuHandleShaderVisible(DescriptorIndex index)
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(int index)
{
if (index < 0 || index >= NumDescriptors)
{
@@ -228,7 +230,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
return _startCpuHandleShaderVisible.Offset(index, Stride);
}
public readonly GpuDescriptorHandle GetGpuHandle(DescriptorIndex index)
public readonly D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int index)
{
if (index < 0 || index >= NumDescriptors)
{
@@ -243,7 +245,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
return _startGpuHandleShaderVisible.Offset(index, Stride);
}
public DescriptorIndex CopyToPersistentHeap(DescriptorIndex index, int count = 1)
public int CopyToPersistentHeap(int index, int count = 1)
{
if (index < _dynamicHeapStart)
{
@@ -256,7 +258,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
return newLocation;
}
public readonly void CopyToShaderVisibleHeap(DescriptorIndex index, int count = 1)
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
{
_device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
}
@@ -267,18 +269,18 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
_heap.Dispose();
_shaderVisibleHeap.Dispose();
DescriptorHeapDescription heapDesc = new()
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = new()
{
Type = HeapType,
NumDescriptors = (uint)numDescriptors,
Flags = DescriptorHeapFlags.None,
Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask = 0
};
fixed (void* heapPtr = &_heap)
{
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
if (hr.Failure)
if (hr.FAILED)
{
return false;
}
@@ -289,12 +291,12 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
if (ShaderVisible)
{
heapDesc.Flags = DescriptorHeapFlags.ShaderVisible;
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
fixed (void* heapPtr = &_shaderVisibleHeap)
{
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
if (hr.Failure)
if (hr.FAILED)
{
return false;
}

View File

@@ -1,7 +1,6 @@
using Ghost.Graphics.Data;
using System.Runtime.CompilerServices;
using Win32.Graphics.Direct3D12;
using Win32.Graphics.Dxgi.Common;
using TerraFX.Interop.DirectX;
namespace Ghost.Graphics.D3D12.Utilities;
@@ -9,19 +8,19 @@ internal unsafe static class D3D12PipelineResource
{
public const int BACK_BUFFER_COUNT = 2;
private readonly static InputElementDescription[] s_inputElementDescs = [
new InputElementDescription{ SemanticName = Vertex.Semantic.position.GetUnsafePointer(), SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
new InputElementDescription{ SemanticName = Vertex.Semantic.normal.GetUnsafePointer(), SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
new InputElementDescription{ SemanticName = Vertex.Semantic.tangent.GetUnsafePointer(), SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
new InputElementDescription{ SemanticName = Vertex.Semantic.uv.GetUnsafePointer(), SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
new InputElementDescription{ SemanticName = Vertex.Semantic.color.GetUnsafePointer(), SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
private readonly static D3D12_INPUT_ELEMENT_DESC[] s_inputElementDescs = [
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.position.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.normal.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.tangent.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.uv.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.color.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
];
public const Format SWAP_CHAIN_BACK_BUFFER_FORMAT = Format.B8G8R8A8Unorm;
public const DXGI_FORMAT SWAP_CHAIN_BACK_BUFFER_FORMAT = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
public static InputLayoutDescription InputLayoutDescription => new()
public static D3D12_INPUT_LAYOUT_DESC InputLayoutDescription => new()
{
pInputElementDescs = (InputElementDescription*)Unsafe.AsPointer(ref s_inputElementDescs[0]),
pInputElementDescs = (D3D12_INPUT_ELEMENT_DESC*)Unsafe.AsPointer(ref s_inputElementDescs[0]),
NumElements = (uint)s_inputElementDescs.Length
};
}

View File

@@ -1,5 +1,163 @@
namespace Ghost.Graphics.D3D12.Utilities;
using Misaki.HighPerformance.LowLevel.Utilities;
using TerraFX.Interop.DirectX;
internal static class D3D12Utility
using static TerraFX.Aliases.D3D12_Alias;
namespace Ghost.Graphics.D3D12.Utilities;
internal unsafe static class ID3D12Resource_Extensions
{
extension(ID3D12Resource resource)
{
public void SetName(ReadOnlySpan<char> name)
{
resource.SetName(name.GetUnsafePtr());
}
}
}
internal static class D3D12_RASTERIZER_DESC_Extensions
{
extension(D3D12_RASTERIZER_DESC)
{
public static D3D12_RASTERIZER_DESC CULL_NONE => Create(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE);
public static D3D12_RASTERIZER_DESC CULL_CLOCKWISE => Create(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_FRONT);
public static D3D12_RASTERIZER_DESC CULL_COUNTER_CLOCKWISE => Create(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_BACK);
public static D3D12_RASTERIZER_DESC WIREFRAME => Create(D3D12_FILL_MODE_WIREFRAME, D3D12_CULL_MODE_NONE);
public static D3D12_RASTERIZER_DESC Create(
D3D12_FILL_MODE fillMode,
D3D12_CULL_MODE cullMode,
bool frontCounterClockwise = false,
int depthBias = D3D12_DEFAULT_DEPTH_BIAS,
float depthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
float slopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
bool depthClipEnable = true,
bool multisampleEnable = true,
bool antialiasedLineEnable = false,
uint forcedSampleCount = 0,
D3D12_CONSERVATIVE_RASTERIZATION_MODE conservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF)
{
return new D3D12_RASTERIZER_DESC
{
FillMode = fillMode,
CullMode = cullMode,
FrontCounterClockwise = frontCounterClockwise ? TRUE : FALSE,
DepthBias = depthBias,
DepthBiasClamp = depthBiasClamp,
SlopeScaledDepthBias = slopeScaledDepthBias,
DepthClipEnable = depthClipEnable ? TRUE : FALSE,
MultisampleEnable = multisampleEnable ? TRUE : FALSE,
AntialiasedLineEnable = antialiasedLineEnable ? TRUE : FALSE,
ForcedSampleCount = forcedSampleCount,
ConservativeRaster = conservativeRaster
};
}
}
}
internal static class D3D12_BLEND_DESC_Extensions
{
extension(D3D12_BLEND_DESC)
{
public static D3D12_BLEND_DESC OPAQUE => Create(D3D12_BLEND_ONE, D3D12_BLEND_ZERO);
public static D3D12_BLEND_DESC ALPHA_BLEND => Create(D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA);
public static D3D12_BLEND_DESC ADDITIVE => Create(D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_ONE);
public static D3D12_BLEND_DESC NON_PREMULTIPLIED => Create(D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA);
public static D3D12_BLEND_DESC Create(D3D12_BLEND srcBlend, D3D12_BLEND destBlend)
{
var blendDesc = new D3D12_BLEND_DESC
{
AlphaToCoverageEnable = false,
IndependentBlendEnable = false
};
for (var i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{
blendDesc.RenderTarget[i].BlendEnable = srcBlend != D3D12_BLEND_ONE || destBlend != D3D12_BLEND_ZERO;
blendDesc.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
blendDesc.RenderTarget[i].SrcBlend = srcBlend;
blendDesc.RenderTarget[i].DestBlend = destBlend;
blendDesc.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[i].SrcBlendAlpha = srcBlend;
blendDesc.RenderTarget[i].DestBlendAlpha = destBlend;
blendDesc.RenderTarget[i].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blendDesc.RenderTarget[i].RenderTargetWriteMask = (byte)D3D12_COLOR_WRITE_ENABLE_ALL;
}
return blendDesc;
}
}
}
internal static class D3D12_DEPTH_STENCIL_DESC_Extensions
{
extension(D3D12_DEPTH_STENCIL_DESC)
{
public static D3D12_DEPTH_STENCIL_DESC NONE => Create(false, false, D3D12_COMPARISON_FUNC_LESS_EQUAL);
public static D3D12_DEPTH_STENCIL_DESC READ => Create(true, false, D3D12_COMPARISON_FUNC_LESS_EQUAL);
public static D3D12_DEPTH_STENCIL_DESC REVERSE_Z => Create(true, true, D3D12_COMPARISON_FUNC_GREATER_EQUAL);
public static D3D12_DEPTH_STENCIL_DESC READ_REVERSE_Z => Create(true, false, D3D12_COMPARISON_FUNC_GREATER_EQUAL);
public static D3D12_DEPTH_STENCIL_DESC Create(bool depthEnable,
bool depthWriteEnable,
D3D12_COMPARISON_FUNC depthFunc,
bool stencilEnable = false,
byte stencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK,
byte stencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK,
D3D12_STENCIL_OP frontStencilFailOp = D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP frontStencilDepthFailOp = D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP frontStencilPassOp = D3D12_STENCIL_OP_KEEP,
D3D12_COMPARISON_FUNC frontStencilFunc = D3D12_COMPARISON_FUNC_ALWAYS,
D3D12_STENCIL_OP backStencilFailOp = D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP backStencilDepthFailOp = D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP backStencilPassOp = D3D12_STENCIL_OP_KEEP,
D3D12_COMPARISON_FUNC backStencilFunc = D3D12_COMPARISON_FUNC_ALWAYS)
{
return new D3D12_DEPTH_STENCIL_DESC
{
DepthEnable = depthEnable,
DepthWriteMask = depthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO,
DepthFunc = depthFunc,
StencilEnable = stencilEnable,
StencilReadMask = stencilReadMask,
StencilWriteMask = stencilWriteMask,
FrontFace = D3D12_DEPTH_STENCILOP_DESC.Create(frontStencilFailOp, frontStencilDepthFailOp, frontStencilPassOp, frontStencilFunc),
BackFace = D3D12_DEPTH_STENCILOP_DESC.Create(backStencilFailOp, backStencilDepthFailOp, backStencilPassOp, backStencilFunc)
};
}
}
}
internal static class D3D12_DEPTH_STENCILOP_DESC_Extensions
{
extension(D3D12_DEPTH_STENCILOP_DESC)
{
public static D3D12_DEPTH_STENCILOP_DESC DEFAULT => Create(D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS);
public static D3D12_DEPTH_STENCILOP_DESC Create(D3D12_STENCIL_OP stencilFailOp, D3D12_STENCIL_OP stencilDepthFailOp, D3D12_STENCIL_OP stencilPassOp, D3D12_COMPARISON_FUNC stencilFunc)
{
return new D3D12_DEPTH_STENCILOP_DESC
{
StencilFailOp = stencilFailOp,
StencilDepthFailOp = stencilDepthFailOp,
StencilPassOp = stencilPassOp,
StencilFunc = stencilFunc
};
}
}
}
internal unsafe static class D3D12MA_Allocation_Extensions
{
extension(ref readonly D3D12MA_Allocation allocation)
{
public bool IsNull => allocation.GetResource() == null
&& allocation.GetHeap() == null
&& allocation.GetSize() == 0;
public bool IsNotNull => !allocation.IsNull;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
using System.Runtime.CompilerServices;
using TerraFX.Interop.Windows;
namespace Ghost.Graphics.D3D12.Utilities;
internal unsafe static class Win32Utility
{
public static void ThrowIfFailed(this HRESULT hr)
{
if (hr.FAILED)
{
throw new InvalidOperationException($"Operation failed with HRESULT: 0x{hr.Value:X8}");
}
}
public static void** GetVoidAddressOf<T>(this ComPtr<T> comPtr)
where T : unmanaged, IUnknown.Interface
{
return (void**)comPtr.GetAddressOf();
}
public static void** ReleaseAndGetVoidAddressOf<T>(this ComPtr<T> comPtr)
where T : unmanaged, IUnknown.Interface
{
return (void**)comPtr.ReleaseAndGetAddressOf();
}
public static ComPtr<T> Move<T>(this ComPtr<T> comPtr)
where T : unmanaged, IUnknown.Interface
{
ComPtr<T> copy = default;
Unsafe.AsRef(in comPtr).Swap(ref copy);
return copy;
}
public static bool HasFlag<T>(this uint flags, T flag)
where T : Enum
{
return (flags & Unsafe.As<T, uint>(ref flag)) != 0;
}
}