Refactor GPU resource management and rendering pipeline

- Introduced `Handle<T>` and `Identifier<T>` for lightweight, strongly-typed resource identifiers.
- Replaced `BitSet` with `UnsafeBitSet` for improved performance and memory safety.
- Refactored `Mesh` and `Material` into `MeshClass` and `MaterialClass` for better GPU resource handling.
- Added `D3D12ResourceDatabase` to centralize GPU resource tracking and lifecycle management.
- Updated `D3D12ShaderCompiler` to load shaders from disk and dynamically populate constant buffers and textures.
- Enhanced `ICommandBuffer` with new upload operations for buffers and textures.
- Refactored `Vertex` struct for simplified memory layout and better performance.
- Updated `MeshBuilder` and rendering logic to align with new resource and shader structures.
- Added `BindlessDescriptor` support to `TextureHandle` and `BufferHandle`.
- Removed unused classes and performed general cleanup.
- Updated unit tests and demos to reflect the new architecture.
This commit is contained in:
2025-09-19 23:20:15 +09:00
parent 6a504cefc8
commit a39f377533
39 changed files with 1669 additions and 826 deletions

View File

@@ -1,4 +1,7 @@
using Ghost.Graphics.D3D12;
using Ghost.Graphics.Data;
using Misaki.HighPerformance.LowLevel.Utilities;
using System.Drawing;
namespace Ghost.Graphics.RHI;
@@ -7,6 +10,11 @@ namespace Ghost.Graphics.RHI;
/// </summary>
public interface ICommandBuffer : IDisposable
{
public CommandBufferType Type
{
get;
}
/// <summary>
/// Begins recording commands into this command buffer
/// </summary>
@@ -22,7 +30,7 @@ public interface ICommandBuffer : IDisposable
/// </summary>
/// <param name="renderTarget">Render target to render into</param>
/// <param name="clearColor">Color to clear the render target with</param>
public void BeginRenderPass(IRenderTarget renderTarget, Color16 clearColor);
public void BeginRenderPass(IRenderTarget renderTarget, Color128 clearColor);
/// <summary>
/// Ends the current render pass
@@ -66,7 +74,7 @@ public interface ICommandBuffer : IDisposable
/// </summary>
/// <param name="mesh">The mesh to be drawn. Must not be null.</param>
/// <param name="material">The material to use for rendering the mesh. Must not be null.</param>
public void DrawMesh(Mesh mesh, Material material);
public void DrawMesh(MeshClass mesh, MaterialClass material);
/// <summary>
/// Dispatches compute threads
@@ -75,6 +83,26 @@ public interface ICommandBuffer : IDisposable
/// <param name="threadGroupCountY">Thread groups in Y dimension</param>
/// <param name="threadGroupCountZ">Thread groups in Z dimension</param>
public void Dispatch(uint threadGroupCountX, uint threadGroupCountY = 1, uint threadGroupCountZ = 1);
/// <summary>
/// Uploads the specified data to the buffer represented by the given handle.
/// </summary>
/// <typeparam name="T">The unmanaged value type of the elements to upload to the buffer.</typeparam>
/// <param name="buffer">A handle to the buffer that will receive the uploaded data.</param>
/// <param name="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type
/// <typeparamref name="T"/>.</param>
public void Upload<T>(BufferHandle buffer, ReadOnlySpan<T> data)
where T : unmanaged;
/// <summary>
/// Uploads texture data to the specified texture resource starting at the given subresource index.
/// </summary>
/// <param name="texture">The texture resource to which the subresource data will be uploaded. Must be a valid, initialized texture handle.</param>
/// <param name="firstSubresource">The index of the first subresource in the texture to receive data. Must be less than the total number of subresources in the texture.</param>
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param>
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
public void Upload(TextureHandle texture, uint firstSubresource, ref SubResourceData subresources, uint numSubresources);
}
/// <summary>
@@ -82,21 +110,21 @@ public interface ICommandBuffer : IDisposable
/// </summary>
public struct ViewportDesc
{
public float X;
public float Y;
public float Width;
public float Height;
public float MinDepth;
public float MaxDepth;
public float x;
public float y;
public float width;
public float height;
public float minDepth;
public float maxDepth;
public ViewportDesc(float width, float height)
{
X = 0;
Y = 0;
Width = width;
Height = height;
MinDepth = 0.0f;
MaxDepth = 1.0f;
x = 0;
y = 0;
this.width = width;
this.height = height;
minDepth = 0.0f;
maxDepth = 1.0f;
}
}
@@ -122,17 +150,28 @@ public struct RectDesc
/// <summary>
/// Resource states
/// </summary>
[Flags]
public enum ResourceState
{
Common = 0,
VertexAndConstantBuffer = 0x1,
IndexBuffer = 0x2,
RenderTarget = 0x4,
UnorderedAccess = 0x8,
DepthWrite = 0x10,
DepthRead = 0x20,
PixelShaderResource = 0x80,
CopyDest = 0x400,
CopySource = 0x800,
VertexAndConstantBuffer = 1 << 0,
IndexBuffer = 1 << 1,
RenderTarget = 1 << 2,
UnorderedAccess = 1 << 3,
DepthWrite = 1 << 4,
DepthRead = 1 << 5,
PixelShaderResource = 1 << 6,
CopyDest = 1 << 7,
CopySource = 1 << 8,
GenericRead = 1 << 9,
IndirectArgument = 1 << 10,
Present = 0,
}
public struct SubResourceData
{
public unsafe void* pData;
public nint rowPitch;
public nint slicePitch;
}

View File

@@ -7,6 +7,11 @@ public interface IGraphicsEngine : IDisposable
get;
}
public IResourceDatabase ResourceDatabase
{
get;
}
public IResourceAllocator ResourceAllocator
{
get;
@@ -27,4 +32,14 @@ public interface IGraphicsEngine : IDisposable
/// <param name="desc">Swap chain description</param>
/// <returns>A new swap chain instance</returns>
public ISwapChain CreateSwapChain(SwapChainDesc desc);
/// <summary>
/// Begins a new rendering frame, preparing the graphics context for drawing operations.
/// </summary>
public void BeginFrame();
/// <summary>
/// Completes the current rendering frame and performs any necessary finalization steps.
/// </summary>
public void EndFrame();
}

View File

@@ -1,3 +1,4 @@
using Ghost.Core;
using Ghost.Graphics.Data;
namespace Ghost.Graphics.RHI;
@@ -15,11 +16,9 @@ public interface IShaderPipeline
public interface IPipelineStateController
{
public void ColectionShader(ReadOnlySpan<Shader> shaders);
public void CompileCollected();
public void CompileShader(Identifier<Shader> id, string shaderPath);
public void PreCookPipelineState();
public IShaderPipeline GetShaderPipeline(Shader shader);
public IShaderPipeline GetShaderPipeline(Identifier<Shader> id);
}

View File

@@ -31,7 +31,7 @@ public interface IRenderDevice : IDisposable
}
/// <summary>
/// Command buffer types matching D3D12 command list types
/// Command buffer types
/// </summary>
public enum CommandBufferType
{

View File

@@ -173,7 +173,8 @@ public struct RenderTargetDesc
Format = desc.Format,
Dimension = desc.Dimension,
MipLevels = desc.MipLevels,
Usage = usage
Usage = usage,
CreationFlags = TextureCreationFlags.Bindless
};
}
}
@@ -245,6 +246,15 @@ public struct TextureDesc
get;
set;
}
/// <summary>
/// Texture creation flags
/// </summary>
public TextureCreationFlags CreationFlags
{
get;
set;
}
}
/// <summary>
@@ -341,3 +351,10 @@ public enum MemoryType
Upload, // CPU-to-GPU memory
Readback // GPU-to-CPU memory
}
[Flags]
public enum TextureCreationFlags
{
None = 0,
Bindless = 1 << 0
}

View File

@@ -4,40 +4,26 @@ namespace Ghost.Graphics.RHI;
public interface IResourceAllocator
{
/// <summary>
/// Creates a render target for off-screen rendering
/// </summary>
/// <param name="desc">Render target description</param>
/// <returns>A new render target instance</returns>
public IRenderTarget CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
/// <summary>
/// Creates a texture resource
/// </summary>
/// <param name="desc">Texture description</param>
/// <returns>A new texture handle point to the resource</returns>
public TextureHandle CreateTextureHandle(ref readonly TextureDesc desc, bool tempResource = false);
public TextureHandle CreateTexture(ref readonly TextureDesc desc, bool tempResource = false);
/// <summary>
/// Creates a texture resource
/// Creates a render target for off-screen rendering
/// </summary>
/// <param name="desc">Texture description</param>
/// <returns>A new texture instance</returns>
public ITexture CreateTexture(ref readonly TextureDesc desc, bool tempResource = false);
/// <param name="desc">Render target description</param>
/// <returns>A new render target instance</returns>
public TextureHandle CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
/// <summary>
/// Creates a buffer resource
/// </summary>
/// <param name="desc">Buffer description</param>
/// <returns>A new buffer handle point to the resource</returns>
public BufferHandle CreateBufferHandle(ref readonly BufferDesc desc, bool tempResource = false);
/// <summary>
/// Creates a buffer resource
/// </summary>
/// <param name="desc">Buffer description</param>
/// <returns>A new buffer instance</returns>
public IBuffer CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false);
public BufferHandle CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false);
/// <summary>
/// Release a resource given its handle

View File

@@ -1,4 +1,5 @@
using Ghost.Graphics.Data;
using Ghost.Core;
using Ghost.Graphics.Data;
namespace Ghost.Graphics.RHI;
@@ -32,4 +33,24 @@ public interface IResourceDatabase
/// </summary>
/// <param name="handle">The handle of the resource to be removed.</param>
public void RemoveResource(ResourceHandle handle);
public Identifier<Mesh> AddMesh(ref readonly Mesh mesh);
public bool HasMesh(Identifier<Mesh> id);
public Mesh GetMesh(Identifier<Mesh> id);
public ref Mesh GetMeshReference(Identifier<Mesh> id);
public void RemoveMesh(Identifier<Mesh> id);
public Identifier<Shader> AddShader(ref readonly Shader shader);
public bool HasShader(Identifier<Shader> id);
public Shader GetShader(Identifier<Shader> id);
public ref Shader GetShaderReference(Identifier<Shader> id);
public void RemoveShader(Identifier<Shader> id);
}