Files
GhostEngine/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs
Misaki 447a4e6904 feat(render): add meshlet rendering and ECS query ref API
Introduces meshlet-based rendering pipeline with new HLSL structures and push constant layouts. Refactors meshlet upload/cooking, updates RenderGraphContext for global/view/instance data, and enhances ECS QueryBuilder with ref returns and [UnscopedRef] for fluent chaining. Improves resource management and disposal patterns, updates D3D12 interop for compatibility, and refines test/app infrastructure. Includes dependency updates, bug fixes, and code cleanups.
2026-03-25 20:27:46 +09:00

190 lines
5.3 KiB
C#

#if DEBUG
#define ENABLE_DEBUG_LAYER
#endif
using Ghost.Core;
using Ghost.Graphics.Core;
using Ghost.Graphics.RHI;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Ghost.Graphics.D3D12;
public static class D3D12GraphicsEngineFactory
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IGraphicsEngine Create(GraphicsEngineDesc desc)
{
return new D3D12GraphicsEngine(desc);
}
}
internal class D3D12GraphicsEngine : IGraphicsEngine
{
private readonly struct CommandBufferReturnEntry
{
public readonly ICommandBuffer commandBuffer;
public readonly ulong returnFrame;
public CommandBufferReturnEntry(ICommandBuffer commandBuffer, ulong returnFrame)
{
this.commandBuffer = commandBuffer;
this.returnFrame = returnFrame;
}
}
private readonly GraphicsEngineDesc _desc;
#if ENABLE_DEBUG_LAYER
private readonly D3D12DebugLayer _debugLayer;
#endif
private readonly D3D12RenderDevice _device;
private readonly DxcShaderCompiler _shaderCompiler;
private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly D3D12ResourceDatabase _resourceDatabase;
private readonly D3D12PipelineLibrary _pipelineLibrary;
private readonly D3D12ResourceAllocator _resourceAllocator;
private readonly Queue<ICommandBuffer> _commandBufferPool;
private readonly Queue<CommandBufferReturnEntry> _commandBufferReturnQueue;
private ulong _currentFrame;
private bool _disposed;
public IRenderDevice Device => _device;
public IShaderCompiler ShaderCompiler => _shaderCompiler;
public IPipelineLibrary PipelineLibrary => _pipelineLibrary;
public IResourceDatabase ResourceDatabase => _resourceDatabase;
public IResourceAllocator ResourceAllocator => _resourceAllocator;
public D3D12GraphicsEngine(GraphicsEngineDesc desc)
{
_desc = desc;
#if ENABLE_DEBUG_LAYER
_debugLayer = new D3D12DebugLayer();
#endif
_device = new D3D12RenderDevice();
_shaderCompiler = new DxcShaderCompiler();
_descriptorAllocator = new D3D12DescriptorAllocator(_device);
_resourceDatabase = new D3D12ResourceDatabase(_descriptorAllocator);
_pipelineLibrary = new D3D12PipelineLibrary(_device, _resourceDatabase);
_resourceAllocator = new D3D12ResourceAllocator(_device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
_commandBufferPool = new Queue<ICommandBuffer>(4);
_commandBufferReturnQueue = new Queue<CommandBufferReturnEntry>(4);
}
~D3D12GraphicsEngine()
{
Dispose();
}
[Conditional("DEBUG")]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
}
public ICommandAllocator CreateCommandAllocator(CommandBufferType type = CommandBufferType.Graphics)
{
return new D3D12CommandAllocator(_device, type);
}
public ICommandBuffer CreateCommandBuffer(CommandBufferType type = CommandBufferType.Graphics)
{
ThrowIfDisposed();
return new D3D12CommandBuffer(
_device,
_pipelineLibrary,
_resourceDatabase,
_resourceAllocator,
_descriptorAllocator,
type);
}
public ICommandBuffer GetPooledCommandBuffer(CommandBufferType type = CommandBufferType.Graphics)
{
if (_commandBufferPool.TryDequeue(out var commandBuffer))
{
return commandBuffer;
}
else
{
return CreateCommandBuffer(type);
}
}
public void ReturnPooledCommandBuffer(ICommandBuffer commandBuffer)
{
_commandBufferReturnQueue.Enqueue(new CommandBufferReturnEntry(commandBuffer, _currentFrame));
}
public ISwapChain CreateSwapChain(SwapChainDesc desc)
{
ThrowIfDisposed();
return new DXGISwapChain(_resourceDatabase, _descriptorAllocator, _device, desc, _desc.FrameBufferCount);
}
public Result BeginFrame(ulong currentFrame)
{
ThrowIfDisposed();
_currentFrame = currentFrame;
_resourceDatabase.BeginFrame(currentFrame);
return Result.Success();
}
public Result EndFrame(ulong completedFrame)
{
ThrowIfDisposed();
_resourceDatabase.EndFrame(completedFrame);
while (_commandBufferReturnQueue.TryPeek(out var entry) && entry.returnFrame <= completedFrame)
{
_commandBufferPool.Enqueue(entry.commandBuffer);
_commandBufferReturnQueue.Dequeue();
}
return Result.Success();
}
public void Dispose()
{
if (_disposed)
{
return;
}
while (_commandBufferReturnQueue.TryDequeue(out var entry))
{
entry.commandBuffer.Dispose();
}
while (_commandBufferPool.TryDequeue(out var cmd))
{
cmd.Dispose();
}
_resourceDatabase.ReleaseAllResourcesImmediately();
_resourceAllocator.Dispose();
_pipelineLibrary.Dispose();
_resourceDatabase.Dispose();
_descriptorAllocator.Dispose();
_shaderCompiler.Dispose();
_device.Dispose();
#if ENABLE_DEBUG_LAYER
_debugLayer.Dispose();
#endif
_disposed = true;
GC.SuppressFinalize(this);
}
}