From fb003da26a4d8c63084ce89f802952a4eabff40b Mon Sep 17 00:00:00 2001 From: Misaki Date: Tue, 11 Nov 2025 16:10:17 +0900 Subject: [PATCH] Updated D3D12Renderer for testing. --- Ghost.Core/Handle.cs | 6 +- Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs | 1 + Ghost.Graphics/D3D12/D3D12Renderer.cs | 154 ++++++++++-------- Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs | 6 + Ghost.Graphics/D3D12/D3D12SwapChain.cs | 10 +- Ghost.Graphics/RHI/IRenderer.cs | 5 +- Ghost.Graphics/RHI/IResourceDatabase.cs | 12 +- 7 files changed, 107 insertions(+), 87 deletions(-) diff --git a/Ghost.Core/Handle.cs b/Ghost.Core/Handle.cs index 8b0a350..dbcf1a3 100644 --- a/Ghost.Core/Handle.cs +++ b/Ghost.Core/Handle.cs @@ -18,7 +18,8 @@ public readonly struct Handle public static Handle Invalid => new(-1, -1); - public bool IsValid => this != Invalid; + public readonly bool IsValid => this != Invalid; + public readonly bool IsNotValid => this == Invalid; public readonly override int GetHashCode() { @@ -63,7 +64,8 @@ public readonly struct Identifier public static Identifier Invalid => new(-1); - public bool IsValid => this != Invalid; + public readonly bool IsValid => this != Invalid; + public readonly bool IsNotValid => this == Invalid; public readonly override int GetHashCode() { diff --git a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs index 4de301b..0824611 100644 --- a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs +++ b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs @@ -26,6 +26,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine public IPipelineLibrary PipelineLibrary => _pipelineLibrary; public IResourceDatabase ResourceDatabase => _resourceDatabase; public IResourceAllocator ResourceAllocator => _resourceAllocator; + public ICommandBuffer CopyCommandBuffer => _copyCommandBuffer; public D3D12GraphicsEngine(IRenderSystem renderSystem) { diff --git a/Ghost.Graphics/D3D12/D3D12Renderer.cs b/Ghost.Graphics/D3D12/D3D12Renderer.cs index 5059719..c0f4c0e 100644 --- a/Ghost.Graphics/D3D12/D3D12Renderer.cs +++ b/Ghost.Graphics/D3D12/D3D12Renderer.cs @@ -3,6 +3,7 @@ using Ghost.Graphics.D3D12.Utilities; using Ghost.Graphics.RHI; using Misaki.HighPerformance.Mathematics; using Ghost.Graphics.Core; +using Ghost.Graphics.RenderPasses; namespace Ghost.Graphics.D3D12; @@ -16,7 +17,7 @@ internal unsafe class D3D12Renderer : IRenderer public ICommandBuffer commandBuffer; public ulong fenceValue; - public FrameResource(IGraphicsEngine graphicsEngine) + public FrameResource(D3D12GraphicsEngine graphicsEngine) { commandBuffer = graphicsEngine.CreateCommandBuffer(); fenceValue = 0; @@ -28,33 +29,37 @@ internal unsafe class D3D12Renderer : IRenderer } } - private readonly ICommandQueue _commandQueue; + private readonly D3D12GraphicsEngine _graphicsEngine; + private readonly D3D12CommandQueue _commandQueue; private readonly FrameResource[] _frameResources; private uint _frameIndex; - private readonly IResourceAllocator _resourceAllocator; + private readonly D3D12ResourceAllocator _resourceAllocator; private readonly D3D12ResourceDatabase _resourceDatabase; - private Handle _customRenderTarget; // User-provided render target - private Handle _offScreenRenderTarget; // Off-screen target for swap chain + private Handle _renderTarget; private ISwapChain? _swapChain; private readonly Lock _lock = new(); private uint2 _currentSize; - private uint _pendingWidth; - private uint _pendingHeight; + private uint2 _pendingSize; private bool _resizeRequested; private bool _disposed; + + // NOTE: Testing only. + private readonly MeshRenderPass _pass; + public uint2 Size => _currentSize; // TODO: Add render passes support // private ImmutableArray _renderPasses; - public D3D12Renderer(IGraphicsEngine graphicsEngine, IResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase) + public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase) { - _commandQueue = graphicsEngine.Device.GraphicsQueue; + _graphicsEngine = graphicsEngine; + _commandQueue = (D3D12CommandQueue)graphicsEngine.Device.GraphicsQueue; _resourceAllocator = resourceAllocator; _resourceDatabase = resourceDatabase; @@ -65,8 +70,11 @@ internal unsafe class D3D12Renderer : IRenderer _frameResources[i] = new FrameResource(graphicsEngine); } - _customRenderTarget = Handle.Invalid; - _offScreenRenderTarget = Handle.Invalid; + _renderTarget = Handle.Invalid; + + + // NOTE: Testing only. + _pass = new(); } ~D3D12Renderer() @@ -74,42 +82,46 @@ internal unsafe class D3D12Renderer : IRenderer Dispose(); } + private void CreateOffScreenRenderTarget(uint width, uint height) + { + var desc = RenderTargetDesc.Color(width, height, 1, TextureFormat.R8G8B8A8_UNorm); + _renderTarget = _resourceAllocator.CreateRenderTarget(in desc); + } + public void SetRenderTarget(Handle renderTarget) { - _customRenderTarget = renderTarget; _swapChain = null; - // Clean up off-screen target when switching to render target mode - _resourceDatabase.ReleaseResource(_offScreenRenderTarget.AsResource()); - _offScreenRenderTarget = Handle.Invalid; + _resourceDatabase.ReleaseResource(_renderTarget.AsResource()); + _renderTarget = renderTarget; } public void SetSwapChain(ISwapChain? swapChain) { - _swapChain = swapChain; - _customRenderTarget = Handle.Invalid; - if (_swapChain != null) { - CreateOrUpdateOffScreenRenderTarget(_swapChain.Width, _swapChain.Height); + _resourceDatabase.ReleaseResource(_renderTarget.AsResource()); } - else + + if (swapChain != null) { - _resourceDatabase.ReleaseResource(_offScreenRenderTarget.AsResource()); - _offScreenRenderTarget = Handle.Invalid; + CreateOffScreenRenderTarget(swapChain.Width, swapChain.Height); } + + _swapChain = swapChain; } - public void RequestResize(uint width, uint height) + public void RequestResize(uint2 newSize ) { lock (_lock) { - if (_pendingWidth == width && _pendingHeight == height) + if (math.all(_pendingSize == newSize)) + { return; + } _resizeRequested = true; - _pendingWidth = width; - _pendingHeight = height; + _pendingSize = newSize; } } @@ -120,11 +132,10 @@ internal unsafe class D3D12Renderer : IRenderer return; } - uint newWidth, newHeight; + uint2 newSize; lock (_lock) { - newWidth = _pendingWidth; - newHeight = _pendingHeight; + newSize = _pendingSize; _resizeRequested = false; } @@ -132,13 +143,14 @@ internal unsafe class D3D12Renderer : IRenderer WaitIdle(); // Resize swap chain if present - _swapChain?.Resize(newWidth, newHeight); - _currentSize = new uint2(newWidth, newHeight); + _swapChain?.Resize(newSize.x, newSize.y); + _currentSize = newSize; // Update off-screen render target size if (_swapChain != null) { - CreateOrUpdateOffScreenRenderTarget(newWidth, newHeight); + _resourceDatabase.ReleaseResource(_renderTarget.AsResource()); + CreateOffScreenRenderTarget(newSize.x, newSize.y); } } @@ -154,32 +166,32 @@ internal unsafe class D3D12Renderer : IRenderer _commandQueue.WaitForValue(frame.fenceValue); } - frame.commandBuffer.Begin(); - - if (_customRenderTarget.IsValid) + if (_renderTarget.IsValid) { - // Render target mode: render directly to custom target - RenderScene(_customRenderTarget, frame.commandBuffer); + frame.commandBuffer.Begin(); + + // NOTE: Temperary solution: render directly to the swap chain back buffer if available. + var rt = _swapChain?.GetCurrentBackBuffer() ?? _renderTarget; + RenderScene(rt, frame.commandBuffer); + + // if (_swapChain != null) + // { + // var backBufferRT = _swapChain.GetCurrentBackBuffer(); + // BlitToDestination(_renderTarget, backBufferRT, frame.commandBuffer); + // } + + frame.commandBuffer.End(); + + _commandQueue.Submit(frame.commandBuffer); + _swapChain?.Present(); + } - else if (_swapChain != null && _offScreenRenderTarget.IsValid) - { - // Swap chain mode: render to off-screen, then blit to back buffer - var backBufferRT = _swapChain.GetCurrentBackBuffer(); - - // For testing, we render directly to the back buffer - RenderScene(backBufferRT, frame.commandBuffer); - //BlitToDestination(_offScreenRenderTarget, backBufferRT, frame.CommandBuffer); - } - - frame.commandBuffer.End(); - - _commandQueue.Submit(frame.commandBuffer); - _swapChain?.Present(); frame.fenceValue = _commandQueue.Signal(_frameIndex); _frameIndex++; } + // TODO: A proper render graph integration. private void RenderScene(Handle target, ICommandBuffer cmd) { var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f }; @@ -206,16 +218,19 @@ internal unsafe class D3D12Renderer : IRenderer cmd.SetViewport(viewport); cmd.SetScissorRect(scissor); - // TODO: Execute render passes - // foreach (var pass in _renderPasses) - // { - // pass.Execute(cmd); - // } + // NOTE: Testing only. + var ctx = new RenderingContext(_graphicsEngine, cmd, _graphicsEngine.CopyCommandBuffer, null!); + if (_frameIndex == 0) + { + _pass.Initialize(ref ctx); + } + + _pass.Execute(ref ctx); cmd.EndRenderPass(); } - private void BlitToDestination(Handle source, Handle destination, ICommandBuffer cmd) + private void BlitToSwapChain(Handle source, Handle destination, ICommandBuffer cmd) { // Handle swap chain back buffer transitions if needed if (_swapChain != null) @@ -231,7 +246,6 @@ internal unsafe class D3D12Renderer : IRenderer // This is a placeholder - in D3D12, you would typically: // 1. Set render target to the destination // 2. Use a full-screen quad/triangle with a shader that samples from the source - // 3. Apply post-processing effects (tone mapping, gamma correction, etc.) // Handle swap chain back buffer transitions if needed if (_swapChain != null) @@ -241,17 +255,6 @@ internal unsafe class D3D12Renderer : IRenderer } } - private void CreateOrUpdateOffScreenRenderTarget(uint width, uint height) - { - if (_offScreenRenderTarget.IsValid) - { - _resourceAllocator.ReleaseResource(_offScreenRenderTarget.AsResource()); - } - - var desc = RenderTargetDesc.Color(width, height, 1, TextureFormat.R8G8B8A8_UNorm); - _offScreenRenderTarget = _resourceAllocator.CreateRenderTarget(in desc); - } - public void WaitIdle() { // Wait for all frame resources to complete @@ -273,14 +276,21 @@ internal unsafe class D3D12Renderer : IRenderer WaitIdle(); + // NOTE: Testing only. + _pass.Cleanup(_resourceDatabase); + + // If using a swap chain, release the off-screen render target. + // Otherwise, the render target is managed externally. + if (_swapChain != null) + { + _resourceDatabase.ReleaseResource(_renderTarget.AsResource()); + } + foreach (ref var frame in _frameResources.AsSpan()) { frame.Dispose(); } - _resourceDatabase.ReleaseResource(_customRenderTarget.AsResource()); - _resourceDatabase.ReleaseResource(_offScreenRenderTarget.AsResource()); - _disposed = true; GC.SuppressFinalize(this); diff --git a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs index afc346c..515aaae 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs @@ -165,6 +165,12 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable return handle; } + public bool HasResource(Handle handle) + { + ObjectDisposedException.ThrowIf(_disposed, this); + return _resources.Contain(handle.id, handle.generation); + } + public ref ResourceRecord GetResourceInfo(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); diff --git a/Ghost.Graphics/D3D12/D3D12SwapChain.cs b/Ghost.Graphics/D3D12/D3D12SwapChain.cs index 23816c4..1e6e557 100644 --- a/Ghost.Graphics/D3D12/D3D12SwapChain.cs +++ b/Ghost.Graphics/D3D12/D3D12SwapChain.cs @@ -1,5 +1,6 @@ using Ghost.Core; using Ghost.Core.Utilities; +using Ghost.Graphics.Core; using Ghost.Graphics.Contracts; using Ghost.Graphics.D3D12.Utilities; using Ghost.Graphics.RHI; @@ -11,8 +12,6 @@ using TerraFX.Interop.Windows; using static TerraFX.Aliases.DXGI_Alias; -using Ghost.Graphics.Core; - namespace Ghost.Graphics.D3D12; /// @@ -120,7 +119,7 @@ internal unsafe class D3D12SwapChain : ISwapChain _swapChain.Get()->GetBuffer(i, backBuffer.IID(), backBuffer.PPV()); backBuffer.Get()->SetName($"SwapChain_BackBuffer_{i}"); - _backBuffers[i] = _resourceDatabase.ImportExternalResource(backBuffer, ResourceState.Present).AsTexture(); + _backBuffers[i] = _resourceDatabase.ImportExternalResource(backBuffer.Move(), ResourceState.Present).AsTexture(); } } @@ -135,10 +134,7 @@ internal unsafe class D3D12SwapChain : ISwapChain var presentFlags = 0u; var syncInterval = vsync ? 1u : 0u; - if (_swapChain.Get()->Present(syncInterval, presentFlags).FAILED) - { - throw new InvalidOperationException("Failed to present swap chain."); - } + ThrowIfFailed(_swapChain.Get()->Present(syncInterval, presentFlags)); } public void Resize(uint width, uint height) diff --git a/Ghost.Graphics/RHI/IRenderer.cs b/Ghost.Graphics/RHI/IRenderer.cs index d2aae47..8260242 100644 --- a/Ghost.Graphics/RHI/IRenderer.cs +++ b/Ghost.Graphics/RHI/IRenderer.cs @@ -39,9 +39,8 @@ public interface IRenderer : IDisposable /// /// Requests a resize operation /// - /// New width - /// New height - public void RequestResize(uint width, uint height); + /// New size + public void RequestResize(uint2 newSize); /// /// Waits for the GPU to complete all work diff --git a/Ghost.Graphics/RHI/IResourceDatabase.cs b/Ghost.Graphics/RHI/IResourceDatabase.cs index b6fe15b..9e4cbbc 100644 --- a/Ghost.Graphics/RHI/IResourceDatabase.cs +++ b/Ghost.Graphics/RHI/IResourceDatabase.cs @@ -25,17 +25,23 @@ public interface IResourceDatabase where T : unmanaged; */ + /// + /// Checks if a resource with the specified handle exists in the database. + /// + /// The handle of the resource to check for existence. + bool HasResource(Handle handle); + /// /// Retrieves the current state of the specified resource. /// - /// The handle that uniquely identifies the resource whose state is to be retrieved. Must not be null. + /// The handle that uniquely identifies the resource whose state is to be retrieved. /// A ResourceState value representing the current state of the resource associated with the specified handle. ResourceState GetResourceState(Handle handle); /// /// Sets the state of the specified resource handle to the given value. /// - /// The handle that identifies the resource whose state will be updated. Cannot be null. + /// The handle that identifies the resource whose state will be updated. /// The new state to assign to the resource represented by . void SetResourceState(Handle handle, ResourceState state); @@ -163,4 +169,4 @@ public interface IResourceDatabase /// The unique identifier of the shader pass to retrieve. /// The corresponding to the specified identifier, or null if no matching shader pass is found. ShaderPass GetShaderPass(ShaderPassKey passKey); -} \ No newline at end of file +}