From b3eeb8d36622cbac4903ce2099cbf3b4655cfbe8 Mon Sep 17 00:00:00 2001 From: Misaki Date: Wed, 5 Nov 2025 09:37:54 +0000 Subject: [PATCH] Add mesh shader support to rendering context and fix some bugs. --- Ghost.Core/Ghost.Core.csproj | 7 --- Ghost.Graphics/Core/RenderingContext.cs | 53 +++++++++++++++++-- Ghost.Graphics/Core/Shader.cs | 10 +++- Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs | 2 +- Ghost.Graphics/Ghost.Graphics.csproj | 4 +- Ghost.Graphics/RHI/ICommandBuffer.cs | 1 + Ghost.Graphics/RenderPasses/MeshRenderPass.cs | 4 +- Ghost.Shader/Ghost.SDL.csproj | 12 +---- 8 files changed, 65 insertions(+), 28 deletions(-) diff --git a/Ghost.Core/Ghost.Core.csproj b/Ghost.Core/Ghost.Core.csproj index 098e41e..22d1ac8 100644 --- a/Ghost.Core/Ghost.Core.csproj +++ b/Ghost.Core/Ghost.Core.csproj @@ -25,12 +25,5 @@ - - - - ..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll - - - diff --git a/Ghost.Graphics/Core/RenderingContext.cs b/Ghost.Graphics/Core/RenderingContext.cs index 7183042..aa1ef93 100644 --- a/Ghost.Graphics/Core/RenderingContext.cs +++ b/Ghost.Graphics/Core/RenderingContext.cs @@ -134,15 +134,17 @@ public unsafe readonly ref struct RenderingContext _resourceDatabase.SetResourceState(texture.AsResource(), sateBefore); } } - +#if false + // TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline. + // This is just a place holder for now for testing purpose. + // TODO: Since we are using mesh shader, we should use dispatch mesh instead of draw calls. public void RenderMesh(Handle mesh, Handle material, string passName) { - //_cmd.DrawMesh(mesh, material); ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh); ref var materialRef = ref _resourceDatabase.GetMaterialReference(material); var shader = _resourceDatabase.GetShaderReference(materialRef.Shader); - shader.TryGetPassKey(passName, out var passKey); + shader.TryGetPassKey(passName, out var passIndex, out var passKey); var hash = new GraphicsPipelineHash { id = passKey, @@ -160,7 +162,7 @@ public unsafe readonly ref struct RenderingContext // for (int i = 0; i < 4; i++) { - ref var cache = ref materialRef.GetPassCache((int)passKey.value); + ref var cache = ref materialRef.GetPassCache(passIndex); _directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource); } @@ -177,6 +179,49 @@ public unsafe readonly ref struct RenderingContext var triangleCount = (uint)meshRef.indices.Count / 3; _directCmb.Draw(3, triangleCount, 0, 0); } +#endif + + // TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline. + // This is just a place holder for now for testing purpose. + // TODO: Since we are using mesh shader, we should use dispatch mesh instead of draw calls. + public void DispatchMesh(Handle mesh, Handle material, string passName, uint numThreadsX) + { + ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh); + ref var materialRef = ref _resourceDatabase.GetMaterialReference(material); + var shader = _resourceDatabase.GetShaderReference(materialRef.Shader); + + shader.TryGetPassKey(passName, out var passIndex, out var passKey); + var hash = new GraphicsPipelineHash + { + id = passKey, + rtvCount = 1, + dsvFormat = TextureFormat.Unknown, + }; + + hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm; + var pipelineKey = hash.GetKey(); + _directCmb.SetPipelineState(pipelineKey); + + // FIX: Get valid root signature. In D3D12, we use fixed root signature layout for bindless rendering. + // However, our code should not assume that blindly. Each pipeline should have contained root signature info even if there are fixed. + // This ensures that future changes to root signature layout can be accommodated. + + // for (int i = 0; i < 4; i++) + { + ref var cache = ref materialRef.GetPassCache(passIndex); + _directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource); + } + + // NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables. + // TODO: Matbe handle the transitional bindless model? +#if false + var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart(); + _commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle); +#endif + + var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX; + _directCmb.DispatchMesh(threadGroupCountX, 1, 1); + } public void ExecuteCopyCommands() { diff --git a/Ghost.Graphics/Core/Shader.cs b/Ghost.Graphics/Core/Shader.cs index f4b937a..d0d59ce 100644 --- a/Ghost.Graphics/Core/Shader.cs +++ b/Ghost.Graphics/Core/Shader.cs @@ -96,6 +96,7 @@ public unsafe class ShaderPass : IResourceReleasable public class Shader : IResourceReleasable, IIdentifierType { private UnsafeArray _passIDs; + // TODO: Optmize lookups with a better data structure if needed private readonly Dictionary _passLookup; // pass name to index private readonly Dictionary> _propertyLookup; // property name to pass index (property name to list of pass indices that contain the property) @@ -137,20 +138,27 @@ public class Shader : IResourceReleasable, IIdentifierType } } + public int GetPassIndex(string passName) + { + return _passLookup.GetValueOrDefault(passName, -1); + } + public ShaderPassKey GetPassKey(int index) { return _passIDs[index]; } - public bool TryGetPassKey(string passName, out ShaderPassKey passID) + public bool TryGetPassKey(string passName, out int passIndex, out ShaderPassKey passID) { var index = _passLookup.GetValueOrDefault(passName, -1); if (index == -1) { + passIndex = -1; passID = new(0); return false; } + passIndex = index; passID = _passIDs[index]; return true; } diff --git a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs index fe68d68..c180b09 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs @@ -106,7 +106,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable private readonly UnsafeSlotMap _meshes; private readonly UnsafeSlotMap _materials; private readonly DynamicArray _shaders; // NOTE: We use a simple list since shader is not frequently added/removed. This can save 4 bytes for each ecs component. - private readonly Dictionary _shaderPasses; + private readonly Dictionary _shaderPasses; // NOTE: The reason we use Dictionary here is that ShaderPassKey is a presistence identifier across multiple application sessions. private bool _disposed; diff --git a/Ghost.Graphics/Ghost.Graphics.csproj b/Ghost.Graphics/Ghost.Graphics.csproj index f876b97..05ac91e 100644 --- a/Ghost.Graphics/Ghost.Graphics.csproj +++ b/Ghost.Graphics/Ghost.Graphics.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/Ghost.Graphics/RHI/ICommandBuffer.cs b/Ghost.Graphics/RHI/ICommandBuffer.cs index 19d04d6..dfa3598 100644 --- a/Ghost.Graphics/RHI/ICommandBuffer.cs +++ b/Ghost.Graphics/RHI/ICommandBuffer.cs @@ -161,6 +161,7 @@ public interface ICommandBuffer : IDisposable /// /// Dispatches ray tracing threads /// + // TODO: This method is not supported yet. void DispatchRay(); /// diff --git a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs index 3ba5840..781f04d 100644 --- a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs +++ b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs @@ -1,10 +1,10 @@ using Ghost.Core; +using Ghost.Graphics.Core; using Ghost.Graphics.Contracts; using Ghost.Graphics.RHI; using Ghost.Graphics.Utilities; using Ghost.SDL.Compiler; using Misaki.HighPerformance.Image; -using Ghost.Graphics.Core; namespace Ghost.Graphics.RenderPasses; @@ -67,7 +67,7 @@ internal unsafe class MeshRenderPass : IRenderPass public void Execute(ref readonly RenderingContext ctx) { - ctx.RenderMesh(_mesh, _material, "Forward"); + ctx.DispatchMesh(_mesh, _material, "Forward", 8); } public void Cleanup(IResourceDatabase resourceDatabase) diff --git a/Ghost.Shader/Ghost.SDL.csproj b/Ghost.Shader/Ghost.SDL.csproj index e5e20c1..c86dc31 100644 --- a/Ghost.Shader/Ghost.SDL.csproj +++ b/Ghost.Shader/Ghost.SDL.csproj @@ -7,17 +7,7 @@ - - - - - - - - - - - +