Files
GhostEngine/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs
Misaki d03eb659fa feat(meshlet): refactor meshlet pipeline & add benchmark
Refactor meshlet build pipeline for robustness and performance.
Rename DxcShaderCompiler to DXCShaderCompiler. Enhance meshlet
data structures with bounds and LOD info. Add fallback mesh
simplification. Remove obsolete MeshRenderPass. Add
MeshoptBenchmark for meshlet build performance. Update mesh
import utilities for correct handedness. Minor bug fixes and
code cleanups.
2026-04-02 17:50:44 +09:00

217 lines
6.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;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
namespace Ghost.Graphics.D3D12;
public static class D3D12GraphicsEngineFactory
{
static D3D12GraphicsEngineFactory()
{
var currentDir = AppContext.BaseDirectory;
var platform = OperatingSystem.IsWindows() ? "win" :
OperatingSystem.IsLinux() ? "linux" :
OperatingSystem.IsMacOS() ? "osx" : "unknown";
var arch = Environment.Is64BitProcess ? "x64" : "x86";
var nativeDllDir = Path.Combine(currentDir, "runtimes", platform + "-" + arch, "native");
AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, libraryName) =>
{
if (libraryName == "dxcompiler")
{
NativeLibrary.TryLoad(Path.Combine(nativeDllDir, "dxil.dll"), out _);
if (NativeLibrary.TryLoad(Path.Combine(nativeDllDir, "dxcompiler.dll"), out var dxcHandle))
{
return dxcHandle;
}
}
return IntPtr.Zero;
};
}
[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);
}
}