From 6a504cefc86f4581356d676d4f81eb31788ec3b3 Mon Sep 17 00:00:00 2001 From: Misaki Date: Tue, 16 Sep 2025 20:55:20 +0900 Subject: [PATCH] Migrate rendering from oop to dod --- Ghost.Core/Ref.cs | 16 -- Ghost.Graphics/D3D12/CommandList.cs | 2 +- Ghost.Graphics/D3D12/D3D12Buffer.cs | 19 +- Ghost.Graphics/D3D12/D3D12CommandBuffer.cs | 2 +- Ghost.Graphics/D3D12/D3D12Renderer.cs | 4 +- .../D3D12/D3D12ResourceAllocator.cs | 71 ++--- Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs | 11 + .../D3D12/Utilities/D3D12PipelineResource.cs | 10 +- Ghost.Graphics/Data/Bounds.cs | 251 ------------------ Ghost.Graphics/Data/Color.cs | 36 +-- .../Data/GraphicsResourceManager.cs | 54 ++++ Ghost.Graphics/Data/Mesh.cs | 127 +++++---- Ghost.Graphics/Data/RenderTexture.cs | 2 +- Ghost.Graphics/Data/ResourceHandle.cs | 8 +- Ghost.Graphics/Data/Vertex.cs | 43 +-- Ghost.Graphics/Ghost.Graphics.csproj | 1 + Ghost.Graphics/RHI/ICommandBuffer.cs | 2 +- Ghost.Graphics/RHI/IResourceAllocator.cs | 12 - Ghost.Graphics/RHI/IResourceDatabase.cs | 35 +++ Ghost.Graphics/Utilities/MeshBuilder.cs | 6 +- 20 files changed, 263 insertions(+), 449 deletions(-) delete mode 100644 Ghost.Core/Ref.cs create mode 100644 Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs delete mode 100644 Ghost.Graphics/Data/Bounds.cs create mode 100644 Ghost.Graphics/Data/GraphicsResourceManager.cs create mode 100644 Ghost.Graphics/RHI/IResourceDatabase.cs diff --git a/Ghost.Core/Ref.cs b/Ghost.Core/Ref.cs deleted file mode 100644 index 64a3636..0000000 --- a/Ghost.Core/Ref.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ghost.Core; - -public ref struct Ref -{ - private ref T _value; - - public ref T Value - { - get => ref _value; - } - - public Ref(ref T value) - { - _value = ref value; - } -} \ No newline at end of file diff --git a/Ghost.Graphics/D3D12/CommandList.cs b/Ghost.Graphics/D3D12/CommandList.cs index 6f7e8dd..d77be30 100644 --- a/Ghost.Graphics/D3D12/CommandList.cs +++ b/Ghost.Graphics/D3D12/CommandList.cs @@ -62,7 +62,7 @@ public unsafe class CommandList _commandList.Ptr->OMSetRenderTargets(1, pRtvHandle, false, pDsvHandle); } - public void ClearRenderTarget(RenderTexture renderTarget, Color128 color) + public void ClearRenderTarget(RenderTexture renderTarget, Color16 color) { renderTarget.ClearColor(this, color); } diff --git a/Ghost.Graphics/D3D12/D3D12Buffer.cs b/Ghost.Graphics/D3D12/D3D12Buffer.cs index 788fe4c..29d238f 100644 --- a/Ghost.Graphics/D3D12/D3D12Buffer.cs +++ b/Ghost.Graphics/D3D12/D3D12Buffer.cs @@ -11,6 +11,7 @@ namespace Ghost.Graphics.D3D12; internal unsafe class D3D12Buffer : IBuffer { private readonly BufferHandle _handle; + private readonly D3D12ResourceAllocator? _allocator; private readonly ComPtr _externalResource; // For externally managed resources private ResourceState _currentState; private void* _mappedPtr; @@ -41,9 +42,11 @@ internal unsafe class D3D12Buffer : IBuffer get; } + public BufferHandle Handle => _handle; + public ResourceState CurrentState => _currentState; - public ID3D12Resource* NativeResource => _externalResource.Get() == null ? _handle.ResourceHandle.GetAllocation().Resource : _externalResource.Get(); + public ID3D12Resource* NativeResource => _externalResource.Get() == null ? _allocator!.GetResource(_handle.ResourceHandle) : _externalResource.Get(); /// /// Constructor for wrapping existing D3D12 resources @@ -51,6 +54,8 @@ internal unsafe class D3D12Buffer : IBuffer public D3D12Buffer(ComPtr resource, ulong size, BufferUsage usage, MemoryType memoryType) { _handle = BufferHandle.Invalid; + _allocator = null; + _externalResource = resource.Move(); Size = size; @@ -62,9 +67,12 @@ internal unsafe class D3D12Buffer : IBuffer /// /// Constructor for allocator-managed buffers /// - public D3D12Buffer(BufferHandle handle, ref readonly BufferDesc desc) + public D3D12Buffer(BufferHandle handle, ref readonly BufferDesc desc, D3D12ResourceAllocator allocator) { _handle = handle; + _allocator = allocator; + + _externalResource = default; Size = desc.Size; Usage = desc.Usage; @@ -75,7 +83,9 @@ internal unsafe class D3D12Buffer : IBuffer public void* Map() { if (_mappedPtr != null) + { return _mappedPtr; + } if (MemoryType != MemoryType.Upload && MemoryType != MemoryType.Readback) { @@ -107,13 +117,16 @@ internal unsafe class D3D12Buffer : IBuffer public void Dispose() { if (_disposed) + { return; + } Unmap(); if (_handle.IsValid) { - _handle.Dispose(); + // Release resource via allocator + _allocator?.ReleaseResource(_handle.ResourceHandle); } else { diff --git a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs index 5cf4f09..0508e64 100644 --- a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs +++ b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs @@ -63,7 +63,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer _isRecording = false; } - public void BeginRenderPass(IRenderTarget renderTarget, Color128 clearColor) + public void BeginRenderPass(IRenderTarget renderTarget, Color16 clearColor) { // TODO: Implement render pass begin throw new NotImplementedException(); diff --git a/Ghost.Graphics/D3D12/D3D12Renderer.cs b/Ghost.Graphics/D3D12/D3D12Renderer.cs index ef9264c..b4a88dc 100644 --- a/Ghost.Graphics/D3D12/D3D12Renderer.cs +++ b/Ghost.Graphics/D3D12/D3D12Renderer.cs @@ -169,7 +169,7 @@ public unsafe class D3D12Renderer : IRenderer private void RenderScene(IRenderTarget target, ICommandBuffer cmd) { - var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f }; + var clearColor = new Color16 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f }; cmd.BeginRenderPass(target, clearColor); @@ -207,7 +207,7 @@ public unsafe class D3D12Renderer : IRenderer // 3. Apply post-processing effects (tone mapping, gamma correction, etc.) // For now, just clear the destination (this should be replaced with actual blit) - var clearColor = new Color128 { r = 0.0f, g = 0.0f, b = 0.0f, a = 1.0f }; + var clearColor = new Color16 { r = 0.0f, g = 0.0f, b = 0.0f, a = 1.0f }; cmd.BeginRenderPass(destination, clearColor); cmd.EndRenderPass(); diff --git a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs index ae2962e..2e374fb 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs @@ -16,15 +16,13 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator allocation.IsNotNull; - public AllocationInfo(in Allocation allocation, uint cpuFenceValue, uint generation) + public AllocationInfo(in Allocation allocation, uint cpuFenceValue) { this.allocation = allocation; this.cpuFenceValue = cpuFenceValue; - this.generation = generation; } public void Dispose() @@ -48,8 +46,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); - private UnsafeQueue _freeSlots = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); + private UnsafeSlotMap _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); private UnsafeQueue _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); private Guid* IID_NULL @@ -99,32 +96,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator 0) - { - id = _freeSlots.Dequeue(); - var info = _allocations[id]; - if (info.Allocated) - { - throw new InvalidOperationException($"ERROR: Resource ID {id} registered as free but still allocated."); - } - - generation = info.generation + 1; - allocInfo = new AllocationInfo(in allocation, _renderSystem.CPUFenceValue, generation); - - _allocations[id] = allocInfo; - } - else - { - id = _allocations.Count; - generation = 0u; - allocInfo = new AllocationInfo(in allocation, _renderSystem.CPUFenceValue, generation); - - _allocations.Add(allocInfo); - } + var id = _allocations.Add(new(in allocation, _renderSystem.CPUFenceValue), out var generation); var handle = new ResourceHandle(id, generation); if (isTemp) @@ -217,19 +189,6 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator 0) { var handle = _temResources.Peek(); - var info = _allocations[handle.id]; - if (info.Allocated && info.cpuFenceValue > _renderSystem.CPUFenceValue) + if (_allocations.TryGetElementAt(handle.id, handle.generation, out var info) + && info.Allocated) { break; } @@ -386,13 +345,13 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator -{ - /// - /// The minimum point contained by the AABB. - /// - /// - /// If any component of is greater than then this AABB is invalid. - /// - /// - public Vector3 Min - { - get; - set; - } - - /// - /// The maximum point contained by the AABB. - /// - /// - /// If any component of is less than then this AABB is invalid. - /// - /// - public Vector3 Max - { - get; - set; - } - - /// - /// Constructs the AABB with the given minimum and maximum. - /// - /// - /// If you have a center and extents, you can call or - /// to create the AABB. - /// - /// Minimum point inside AABB. - /// Maximum point inside AABB. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bounds(Vector3 min, Vector3 max) - { - Min = min; - Max = max; - } - - /// - /// Creates the AABB from a center and extents. - /// - /// - /// This function takes full extents. It is the distance between and . - /// If you have half extents, you can call . - /// - /// Center of AABB. - /// Full extents of AABB. - /// AABB created from inputs. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bounds CreateFromCenterAndExtents(Vector3 center, Vector3 extents) - { - return CreateFromCenterAndHalfExtents(center, extents * 0.5f); - } - - /// - /// Creates the AABB from a center and half extents. - /// - /// - /// This function takes half extents. It is half the distance between and . - /// If you have full extents, you can call . - /// - /// Center of AABB. - /// Half extents of AABB. - /// AABB created from inputs. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bounds CreateFromCenterAndHalfExtents(Vector3 center, Vector3 halfExtents) - { - return new Bounds(center - halfExtents, center + halfExtents); - } - - /// - /// Creates a new AABB with zero extents, centered at the origin. - /// - public static Bounds Zero - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return new Bounds(Vector3.Zero, Vector3.Zero); - } - } - - /// - /// Computes the extents of the AABB. - /// - /// - /// Extents is the componentwise distance between min and max. - /// - public readonly Vector3 Extents => Max - Min; - - /// - /// Computes the half extents of the AABB. - /// - /// - /// HalfExtents is half of the componentwise distance between min and max. Subtracting HalfExtents from Center - /// gives Min and adding HalfExtents to Center gives Max. - /// - public readonly Vector3 HalfExtents => (Max - Min) * 0.5f; - - /// - /// Computes the center of the AABB. - /// - public readonly Vector3 Center => (Max + Min) * 0.5f; - - /// - /// Check if the AABB is valid. - /// - /// - /// An AABB is considered valid if is componentwise less than or equal to . - /// - /// True if is componentwise less than or equal to . - public readonly bool IsValid => Vector3.Dot(Min, Min) <= Vector3.Dot(Max, Max); - - /// - /// Computes the surface area for this axis aligned bounding box. - /// - public readonly float SurfaceArea - { - get - { - var diff = Max - Min; - return 2 * Vector3.Dot(diff, new Vector3(diff.Y, diff.Z, diff.X)); - } - } - - /// - /// Tests if the input point is contained by the AABB. - /// - /// Point to test. - /// True if AABB contains the input point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool Contains(Vector3 point) => Vector3.Dot(point, point) >= Vector3.Dot(Min, Min) && Vector3.Dot(point, point) <= Vector3.Dot(Max, Max); - - /// - /// Tests if the input AABB is contained entirely by this AABB. - /// - /// AABB to test. - /// True if input AABB is contained entirely by this AABB. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool Contains(Bounds aabb) => Vector3.Dot(Min, Min) <= Vector3.Dot(aabb.Min, aabb.Min) && Vector3.Dot(Max, Max) >= Vector3.Dot(aabb.Max, aabb.Max); - - /// - /// Tests if the input AABB overlaps this AABB. - /// - /// AABB to test. - /// True if input AABB overlaps with this AABB. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool Overlaps(Bounds aabb) - { - return Vector3.Dot(Max, Max) >= Vector3.Dot(aabb.Min, aabb.Min) && Vector3.Dot(Min, Min) <= Vector3.Dot(aabb.Max, aabb.Max); - } - - /// - /// Expands the AABB by the given signed distance. - /// - /// - /// Positive distance expands the AABB while negative distance shrinks the AABB. - /// - /// Signed distance to expand the AABB with. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Expand(float signedDistance) - { - Min -= new Vector3(signedDistance); - Max += new Vector3(signedDistance); - } - - /// - /// Encapsulates the given AABB. - /// - /// - /// Modifies this AABB so that it contains the given AABB. If the given AABB is already contained by this AABB, - /// then this AABB doesn't change. - /// - /// - /// AABB to encapsulate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Encapsulate(Bounds aabb) - { - Min = Vector3.Min(Min, aabb.Min); - Max = Vector3.Max(Max, aabb.Max); - } - - /// - /// Encapsulate the given point. - /// - /// - /// Modifies this AABB so that it contains the given point. If the given point is already contained by this AABB, - /// then this AABB doesn't change. - /// - /// - /// Point to encapsulate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Encapsulate(Vector3 point) - { - Min = Vector3.Min(Min, point); - Max = Vector3.Max(Max, point); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bounds other) - { - return Min.Equals(other.Min) && Max.Equals(other.Max); - } - - public override bool Equals(object? obj) - { - if (obj is Bounds bounds) - { - return Equals(bounds); - } - - return false; - } - public static bool operator ==(Bounds left, Bounds right) - { - return left.Equals(right); - } - - public static bool operator !=(Bounds left, Bounds right) - { - return !(left == right); - } - - public override int GetHashCode() - { - unchecked - { - var hash = 17; - hash = hash * 31 + Min.GetHashCode(); - hash = hash * 31 + Max.GetHashCode(); - return hash; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly override string ToString() - { - return string.Format("Bounds({0}, {1})", Min, Max); - } -} \ No newline at end of file diff --git a/Ghost.Graphics/Data/Color.cs b/Ghost.Graphics/Data/Color.cs index c4112cd..6632a19 100644 --- a/Ghost.Graphics/Data/Color.cs +++ b/Ghost.Graphics/Data/Color.cs @@ -4,17 +4,17 @@ using System.Runtime.InteropServices; namespace Ghost.Graphics.Data; /// -/// Represents a color with 32-bit components."/> +/// Represents a color with 4 bytes components. /// [StructLayout(LayoutKind.Sequential, Size = 4)] -public struct Color32 : IEquatable +public struct Color4 : IEquatable { public byte r; public byte g; public byte b; public byte a; - public Color32(byte r, byte g, byte b, byte a) + public Color4(byte r, byte g, byte b, byte a) { this.r = r; this.g = g; @@ -22,24 +22,24 @@ public struct Color32 : IEquatable this.a = a; } - public Color32(Color color) + public Color4(Color color) : this(color.R, color.G, color.B, color.A) { } - public Color32(Color128 color128) + public Color4(Color16 color128) : this((byte)(color128.r * 255.0f), (byte)(color128.g * 255.0f), (byte)(color128.b * 255.0f), (byte)(color128.a * 255.0f)) { } - public readonly bool Equals(Color32 other) + public readonly bool Equals(Color4 other) { return r == other.r && g == other.g && b == other.b && a == other.a; } public override readonly bool Equals(object? obj) { - return obj is Color32 color && Equals(color); + return obj is Color4 color && Equals(color); } public override readonly int GetHashCode() @@ -47,29 +47,29 @@ public struct Color32 : IEquatable return HashCode.Combine(r, g, b, a); } - public static bool operator ==(Color32 left, Color32 right) + public static bool operator ==(Color4 left, Color4 right) { return left.Equals(right); } - public static bool operator !=(Color32 left, Color32 right) + public static bool operator !=(Color4 left, Color4 right) { return !(left == right); } } /// -/// Represents a color with 128-bit components. +/// Represents a color with 16 bytes components. /// [StructLayout(LayoutKind.Sequential, Size = 16)] -public struct Color128 : IEquatable +public struct Color16 : IEquatable { public float r; public float g; public float b; public float a; - public Color128(float r, float g, float b, float a) + public Color16(float r, float g, float b, float a) { this.r = r; this.g = g; @@ -77,24 +77,24 @@ public struct Color128 : IEquatable this.a = a; } - public Color128(Color color) + public Color16(Color color) : this(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f) { } - public Color128(Color32 color32) + public Color16(Color4 color32) : this(color32.r / 255.0f, color32.g / 255.0f, color32.b / 255.0f, color32.a / 255.0f) { } - public readonly bool Equals(Color128 other) + public readonly bool Equals(Color16 other) { return r.Equals(other.r) && g.Equals(other.g) && b.Equals(other.b) && a.Equals(other.a); } public override readonly bool Equals(object? obj) { - return obj is Color128 color && Equals(color); + return obj is Color16 color && Equals(color); } public readonly override int GetHashCode() @@ -102,12 +102,12 @@ public struct Color128 : IEquatable return HashCode.Combine(r, g, b, a); } - public static bool operator ==(Color128 left, Color128 right) + public static bool operator ==(Color16 left, Color16 right) { return left.Equals(right); } - public static bool operator !=(Color128 left, Color128 right) + public static bool operator !=(Color16 left, Color16 right) { return !(left == right); } diff --git a/Ghost.Graphics/Data/GraphicsResourceManager.cs b/Ghost.Graphics/Data/GraphicsResourceManager.cs new file mode 100644 index 0000000..6c98e28 --- /dev/null +++ b/Ghost.Graphics/Data/GraphicsResourceManager.cs @@ -0,0 +1,54 @@ +namespace Ghost.Graphics.Data; + +public struct BatchMaterialID : IEquatable +{ + public uint value; + + public static BatchMaterialID Null => new() { value = 0 }; + + public override int GetHashCode() + { + return value.GetHashCode(); + } + + public readonly override bool Equals(object? obj) + { + return obj is BatchMaterialID id && Equals(id); + } + + public readonly bool Equals(BatchMaterialID other) + { + return value == other.value; + } + + public readonly int CompareTo(BatchMaterialID other) + { + return value.CompareTo(other.value); + } + + public static bool operator ==(BatchMaterialID a, BatchMaterialID b) + { + return a.Equals(b); + } + + public static bool operator !=(BatchMaterialID a, BatchMaterialID b) + { + return !a.Equals(b); + } +} + +internal class GraphicsResourceManager +{ + private readonly Dictionary _materials = new(); + private readonly Dictionary _meshes = new(); + + public Material GetMaterial(BatchMaterialID id) + { + return _materials.TryGetValue(id, out var material) ? material : Material.Null; + } + + public MeshHandle GetMesh(BatchMeshID id) + { + return _meshes.TryGetValue(id, out var mesh) ? mesh : MeshHandle.Invalid; + } +} \ No newline at end of file diff --git a/Ghost.Graphics/Data/Mesh.cs b/Ghost.Graphics/Data/Mesh.cs index 0994579..154289d 100644 --- a/Ghost.Graphics/Data/Mesh.cs +++ b/Ghost.Graphics/Data/Mesh.cs @@ -3,6 +3,7 @@ using Ghost.Graphics.RHI; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Helpers; +using Misaki.HighPerformance.Mathematics.Geometry; using System.Numerics; using System.Runtime.CompilerServices; using Win32.Graphics.Direct3D12; @@ -10,19 +11,85 @@ using Win32.Graphics.Dxgi.Common; namespace Ghost.Graphics.Data; +/// +/// The CPU-side mesh data structure. +/// +public struct MeshData +{ + public UnsafeList vertices; + public UnsafeList indices; + public AABB boundingBox; + public MeshHandle handle; + + public MeshData() + { + handle = MeshHandle.Invalid; + } +} + +/// +/// The GPU-side mesh handle containing buffer references. +/// +public struct MeshHandle +{ + public BufferHandle vertexBuffer; + public BufferHandle indexBuffer; + + public static MeshHandle Invalid => new() { vertexBuffer = BufferHandle.Invalid, indexBuffer = BufferHandle.Invalid }; + + public readonly bool IsValid => vertexBuffer.IsValid && indexBuffer.IsValid; +} + +public struct BatchMeshID : IEquatable +{ + public int value; + + public static BatchMeshID Null => new() { value = -1 }; + + public readonly override int GetHashCode() + { + return value.GetHashCode(); + } + + public readonly override bool Equals(object? obj) + { + return obj is BatchMeshID id && Equals(id); + } + + public readonly bool Equals(BatchMeshID other) + { + return value == other.value; + } + + public readonly int CompareTo(BatchMeshID other) + { + return value.CompareTo(other.value); + } + + public static bool operator ==(BatchMeshID a, BatchMeshID b) + { + return a.Equals(b); + } + + public static bool operator !=(BatchMeshID a, BatchMeshID b) + { + return !a.Equals(b); + } +} + public unsafe sealed class Mesh : IDisposable { private UnsafeList _vertices; private UnsafeList _indices; - private Bounds _boundingBox; + private AABB _boundingBox; private IBuffer? _vertexBuffer; private IBuffer? _indexBuffer; public Span Vertices => _vertices.AsSpan(); public Span Indices => _indices.AsSpan(); - public Bounds BoundingBox => _boundingBox; + public AABB BoundingBox => _boundingBox; public uint VertexCount => (uint)_vertices.Count; public uint IndexCount => (uint)_indices.Count; @@ -296,62 +363,6 @@ public unsafe sealed class Mesh : IDisposable CreateBindlessDescriptors(); } - /// - /// Creates SRVs for vertex and index buffers in the bindless descriptor heap - /// - private void CreateBindlessDescriptors() - { - if (_vertexBuffer == null || _indexBuffer == null) - { - return; - } - - // Allocate new descriptors from the descriptor allocator - _vertexBufferDescriptor = GraphicsPipeline.DescriptorAllocator.AllocateBindless(); - _indexBufferDescriptor = GraphicsPipeline.DescriptorAllocator.AllocateBindless(); - - var device = GraphicsPipeline.GraphicsDevice.NativeDevice.Ptr; - - var vertexSrvDesc = new ShaderResourceViewDescription - { - Format = Format.R32Typeless, - ViewDimension = SrvDimension.Buffer, - Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, - Anonymous = new() - { - Buffer = new() - { - FirstElement = 0, - NumElements = (uint)(_vertexBuffer.GPUAddress != 0 ? (VertexCount * sizeof(Vertex)) / 4 : 0), // Divide by 4 for R32 format - StructureByteStride = 0, - Flags = BufferSrvFlags.Raw - } - } - }; - - device->CreateShaderResourceView(_vertexBuffer.NativeResource.Ptr, &vertexSrvDesc, _vertexBufferDescriptor.CpuHandle); - - var indexSrvDesc = new ShaderResourceViewDescription - { - Format = Format.R32Typeless, - ViewDimension = SrvDimension.Buffer, - Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, - Anonymous = new() - { - Buffer = new() - { - FirstElement = 0, - NumElements = IndexCount, - StructureByteStride = 0, - Flags = BufferSrvFlags.Raw - } - } - }; - - device->CreateShaderResourceView(_indexBuffer.NativeResource.Ptr, &indexSrvDesc, _indexBufferDescriptor.CpuHandle); - } - - internal void MarkNoLongerReadable() { _vertices.Dispose(); diff --git a/Ghost.Graphics/Data/RenderTexture.cs b/Ghost.Graphics/Data/RenderTexture.cs index bd449e6..23ec932 100644 --- a/Ghost.Graphics/Data/RenderTexture.cs +++ b/Ghost.Graphics/Data/RenderTexture.cs @@ -206,7 +206,7 @@ public unsafe class RenderTexture : Texture /// /// Command list to record clear commands /// Color to clear to - public void ClearColor(CommandList commandList, Color128 clearColor) + public void ClearColor(CommandList commandList, Color16 clearColor) { ThrowIfDisposed(); diff --git a/Ghost.Graphics/Data/ResourceHandle.cs b/Ghost.Graphics/Data/ResourceHandle.cs index cf251f1..c512fbd 100644 --- a/Ghost.Graphics/Data/ResourceHandle.cs +++ b/Ghost.Graphics/Data/ResourceHandle.cs @@ -8,17 +8,17 @@ public readonly struct ResourceHandle : IEquatable private const int _INVALID_ID = -1; public readonly int id; - public readonly uint generation; + public readonly int generation; - public static ResourceHandle Invalid => new(-1, 0); + public static ResourceHandle Invalid => new(_INVALID_ID, _INVALID_ID); - internal ResourceHandle(int id, uint generation) + internal ResourceHandle(int id, int generation) { this.id = id; this.generation = generation; } - public bool IsValid => id != _INVALID_ID && generation >= 0; + public bool IsValid => id != _INVALID_ID && generation != _INVALID_ID; public bool Equals(ResourceHandle other) { diff --git a/Ghost.Graphics/Data/Vertex.cs b/Ghost.Graphics/Data/Vertex.cs index 66d6935..16eee45 100644 --- a/Ghost.Graphics/Data/Vertex.cs +++ b/Ghost.Graphics/Data/Vertex.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using Misaki.HighPerformance.Mathematics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -7,7 +7,7 @@ using Win32.Graphics.Dxgi.Common; namespace Ghost.Graphics.Data; [StructLayout(LayoutKind.Sequential)] -public struct Vertex(Vector4 position, Vector4 normal, Vector4 tangent, Color128 color, Vector4 uv) +public struct Vertex { public unsafe struct Semantic { @@ -19,40 +19,49 @@ public struct Vertex(Vector4 position, Vector4 normal, Vector4 tangent, Color128 private static readonly byte[] s_colorBytes = Encoding.UTF8.GetBytes("COLOR"); private static readonly byte[] s_uvBytes = Encoding.UTF8.GetBytes("TEXCOORD"); - public static byte* PositionName => (byte*)Unsafe.AsPointer(ref s_positionBytes[0]); - public static byte* NormalName => (byte*)Unsafe.AsPointer(ref s_normalBytes[0]); - public static byte* TangentName => (byte*)Unsafe.AsPointer(ref s_tangentBytes[0]); - public static byte* ColorName => (byte*)Unsafe.AsPointer(ref s_colorBytes[0]); - public static byte* UVName => (byte*)Unsafe.AsPointer(ref s_uvBytes[0]); + public static byte* pPositionName => (byte*)Unsafe.AsPointer(ref s_positionBytes[0]); + public static byte* pNormalName => (byte*)Unsafe.AsPointer(ref s_normalBytes[0]); + public static byte* pTangentName => (byte*)Unsafe.AsPointer(ref s_tangentBytes[0]); + public static byte* pColorName => (byte*)Unsafe.AsPointer(ref s_colorBytes[0]); + public static byte* pUVName => (byte*)Unsafe.AsPointer(ref s_uvBytes[0]); } - public Vector4 Position + public float4 Position { get; set; - } = position; + } - public Vector4 Normal + public float4 Normal { get; set; - } = normal; + } - public Vector4 Tangent + public float4 Tangent { get; set; - } = tangent; + } - public Color128 Color + public Color16 Color { get; set; - } = color; + } - public Vector4 UV + public float4 UV { get; set; - } = uv; + } + + public Vertex(float4 position, float4 normal, float4 tangent, Color16 color, float4 uv) + { + Position = position; + Normal = normal; + Tangent = tangent; + Color = color; + UV = uv; + } } \ No newline at end of file diff --git a/Ghost.Graphics/Ghost.Graphics.csproj b/Ghost.Graphics/Ghost.Graphics.csproj index 4a3e50f..1030df1 100644 --- a/Ghost.Graphics/Ghost.Graphics.csproj +++ b/Ghost.Graphics/Ghost.Graphics.csproj @@ -18,6 +18,7 @@ + diff --git a/Ghost.Graphics/RHI/ICommandBuffer.cs b/Ghost.Graphics/RHI/ICommandBuffer.cs index 55c7bd4..8b4a7bc 100644 --- a/Ghost.Graphics/RHI/ICommandBuffer.cs +++ b/Ghost.Graphics/RHI/ICommandBuffer.cs @@ -22,7 +22,7 @@ public interface ICommandBuffer : IDisposable /// /// Render target to render into /// Color to clear the render target with - public void BeginRenderPass(IRenderTarget renderTarget, Color128 clearColor); + public void BeginRenderPass(IRenderTarget renderTarget, Color16 clearColor); /// /// Ends the current render pass diff --git a/Ghost.Graphics/RHI/IResourceAllocator.cs b/Ghost.Graphics/RHI/IResourceAllocator.cs index 65512be..5331a22 100644 --- a/Ghost.Graphics/RHI/IResourceAllocator.cs +++ b/Ghost.Graphics/RHI/IResourceAllocator.cs @@ -44,16 +44,4 @@ public interface IResourceAllocator /// /// Resource handle public void ReleaseResource(ResourceHandle handle); -} - -internal interface IResourceAllocator : IResourceAllocator - where T : unmanaged -{ - /// - /// Get the raw gpu resource pointer from a resource handle - /// - /// The type of the resource. - /// Resource handle - /// Pointer to the resource - public unsafe T* GetResource(ResourceHandle handle); } \ No newline at end of file diff --git a/Ghost.Graphics/RHI/IResourceDatabase.cs b/Ghost.Graphics/RHI/IResourceDatabase.cs new file mode 100644 index 0000000..50fbbd4 --- /dev/null +++ b/Ghost.Graphics/RHI/IResourceDatabase.cs @@ -0,0 +1,35 @@ +using Ghost.Graphics.Data; + +namespace Ghost.Graphics.RHI; + +public interface IResourceDatabase +{ + /// + /// Get the raw gpu resource pointer from a resource handle + /// + /// The type of the resource. + /// Resource handle + /// Pointer to the resource + public unsafe T* GetResource(ResourceHandle handle) + where T: unmanaged; + + /// + /// 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. + /// A ResourceState value representing the current state of the resource associated with the specified handle. + public ResourceState GetResourceState(ResourceHandle 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 new state to assign to the resource represented by . + public void SetResourceState(ResourceHandle handle, ResourceState state); + + /// + /// Removes a resource from the database using its handle. + /// + /// The handle of the resource to be removed. + public void RemoveResource(ResourceHandle handle); +} \ No newline at end of file diff --git a/Ghost.Graphics/Utilities/MeshBuilder.cs b/Ghost.Graphics/Utilities/MeshBuilder.cs index aeb0d62..721832b 100644 --- a/Ghost.Graphics/Utilities/MeshBuilder.cs +++ b/Ghost.Graphics/Utilities/MeshBuilder.cs @@ -8,7 +8,7 @@ public static class MeshBuilder /// /// Creates a unit cube centered at the origin with size 1. /// - public static Mesh CreateCube(float size = 1.0f, Color128 color = default) + public static Mesh CreateCube(float size = 1.0f, Color16 color = default) { var half = size * 0.5f; var mesh = new Mesh(24, 36); @@ -61,7 +61,7 @@ public static class MeshBuilder /// /// Creates a plane on the XZ axis centered at the origin. /// - public static Mesh CreatePlane(float width = 1.0f, float depth = 1.0f, Color128 color = default) + public static Mesh CreatePlane(float width = 1.0f, float depth = 1.0f, Color16 color = default) { var hw = width * 0.5f; var hd = depth * 0.5f; @@ -83,7 +83,7 @@ public static class MeshBuilder /// /// Creates a UV sphere centered at the origin. /// - public static Mesh CreateSphere(int latitudeSegments = 16, int longitudeSegments = 24, float radius = 0.5f, Color128 color = default) + public static Mesh CreateSphere(int latitudeSegments = 16, int longitudeSegments = 24, float radius = 0.5f, Color16 color = default) { var mesh = new Mesh((latitudeSegments + 1) * (longitudeSegments + 1), latitudeSegments * longitudeSegments * 6);