Migrate rendering from oop to dod
This commit is contained in:
@@ -1,16 +0,0 @@
|
|||||||
namespace Ghost.Core;
|
|
||||||
|
|
||||||
public ref struct Ref<T>
|
|
||||||
{
|
|
||||||
private ref T _value;
|
|
||||||
|
|
||||||
public ref T Value
|
|
||||||
{
|
|
||||||
get => ref _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Ref(ref T value)
|
|
||||||
{
|
|
||||||
_value = ref value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -62,7 +62,7 @@ public unsafe class CommandList
|
|||||||
_commandList.Ptr->OMSetRenderTargets(1, pRtvHandle, false, pDsvHandle);
|
_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);
|
renderTarget.ClearColor(this, color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
internal unsafe class D3D12Buffer : IBuffer
|
internal unsafe class D3D12Buffer : IBuffer
|
||||||
{
|
{
|
||||||
private readonly BufferHandle _handle;
|
private readonly BufferHandle _handle;
|
||||||
|
private readonly D3D12ResourceAllocator? _allocator;
|
||||||
private readonly ComPtr<ID3D12Resource> _externalResource; // For externally managed resources
|
private readonly ComPtr<ID3D12Resource> _externalResource; // For externally managed resources
|
||||||
private ResourceState _currentState;
|
private ResourceState _currentState;
|
||||||
private void* _mappedPtr;
|
private void* _mappedPtr;
|
||||||
@@ -41,9 +42,11 @@ internal unsafe class D3D12Buffer : IBuffer
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferHandle Handle => _handle;
|
||||||
|
|
||||||
public ResourceState CurrentState => _currentState;
|
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();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor for wrapping existing D3D12 resources
|
/// Constructor for wrapping existing D3D12 resources
|
||||||
@@ -51,6 +54,8 @@ internal unsafe class D3D12Buffer : IBuffer
|
|||||||
public D3D12Buffer(ComPtr<ID3D12Resource> resource, ulong size, BufferUsage usage, MemoryType memoryType)
|
public D3D12Buffer(ComPtr<ID3D12Resource> resource, ulong size, BufferUsage usage, MemoryType memoryType)
|
||||||
{
|
{
|
||||||
_handle = BufferHandle.Invalid;
|
_handle = BufferHandle.Invalid;
|
||||||
|
_allocator = null;
|
||||||
|
|
||||||
_externalResource = resource.Move();
|
_externalResource = resource.Move();
|
||||||
|
|
||||||
Size = size;
|
Size = size;
|
||||||
@@ -62,9 +67,12 @@ internal unsafe class D3D12Buffer : IBuffer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor for allocator-managed buffers
|
/// Constructor for allocator-managed buffers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public D3D12Buffer(BufferHandle handle, ref readonly BufferDesc desc)
|
public D3D12Buffer(BufferHandle handle, ref readonly BufferDesc desc, D3D12ResourceAllocator allocator)
|
||||||
{
|
{
|
||||||
_handle = handle;
|
_handle = handle;
|
||||||
|
_allocator = allocator;
|
||||||
|
|
||||||
|
_externalResource = default;
|
||||||
|
|
||||||
Size = desc.Size;
|
Size = desc.Size;
|
||||||
Usage = desc.Usage;
|
Usage = desc.Usage;
|
||||||
@@ -75,7 +83,9 @@ internal unsafe class D3D12Buffer : IBuffer
|
|||||||
public void* Map()
|
public void* Map()
|
||||||
{
|
{
|
||||||
if (_mappedPtr != null)
|
if (_mappedPtr != null)
|
||||||
|
{
|
||||||
return _mappedPtr;
|
return _mappedPtr;
|
||||||
|
}
|
||||||
|
|
||||||
if (MemoryType != MemoryType.Upload && MemoryType != MemoryType.Readback)
|
if (MemoryType != MemoryType.Upload && MemoryType != MemoryType.Readback)
|
||||||
{
|
{
|
||||||
@@ -107,13 +117,16 @@ internal unsafe class D3D12Buffer : IBuffer
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Unmap();
|
Unmap();
|
||||||
|
|
||||||
if (_handle.IsValid)
|
if (_handle.IsValid)
|
||||||
{
|
{
|
||||||
_handle.Dispose();
|
// Release resource via allocator
|
||||||
|
_allocator?.ReleaseResource(_handle.ResourceHandle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginRenderPass(IRenderTarget renderTarget, Color128 clearColor)
|
public void BeginRenderPass(IRenderTarget renderTarget, Color16 clearColor)
|
||||||
{
|
{
|
||||||
// TODO: Implement render pass begin
|
// TODO: Implement render pass begin
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public unsafe class D3D12Renderer : IRenderer
|
|||||||
|
|
||||||
private void RenderScene(IRenderTarget target, ICommandBuffer cmd)
|
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);
|
cmd.BeginRenderPass(target, clearColor);
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ public unsafe class D3D12Renderer : IRenderer
|
|||||||
// 3. Apply post-processing effects (tone mapping, gamma correction, etc.)
|
// 3. Apply post-processing effects (tone mapping, gamma correction, etc.)
|
||||||
|
|
||||||
// For now, just clear the destination (this should be replaced with actual blit)
|
// 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.BeginRenderPass(destination, clearColor);
|
||||||
cmd.EndRenderPass();
|
cmd.EndRenderPass();
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,13 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
{
|
{
|
||||||
public readonly Allocation allocation;
|
public readonly Allocation allocation;
|
||||||
public readonly uint cpuFenceValue;
|
public readonly uint cpuFenceValue;
|
||||||
public readonly uint generation;
|
|
||||||
|
|
||||||
public bool Allocated => allocation.IsNotNull;
|
public bool Allocated => allocation.IsNotNull;
|
||||||
|
|
||||||
public AllocationInfo(in Allocation allocation, uint cpuFenceValue, uint generation)
|
public AllocationInfo(in Allocation allocation, uint cpuFenceValue)
|
||||||
{
|
{
|
||||||
this.allocation = allocation;
|
this.allocation = allocation;
|
||||||
this.cpuFenceValue = cpuFenceValue;
|
this.cpuFenceValue = cpuFenceValue;
|
||||||
this.generation = generation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -48,8 +46,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
private readonly RenderSystem _renderSystem;
|
private readonly RenderSystem _renderSystem;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
|
|
||||||
private UnsafeList<AllocationInfo> _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
private UnsafeSlotMap<AllocationInfo> _allocations = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
private UnsafeQueue<int> _freeSlots = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
|
||||||
private UnsafeQueue<ResourceHandle> _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
private UnsafeQueue<ResourceHandle> _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
|
|
||||||
private Guid* IID_NULL
|
private Guid* IID_NULL
|
||||||
@@ -99,32 +96,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
|
|
||||||
private ResourceHandle TrackResource(ref readonly Allocation allocation, bool isTemp)
|
private ResourceHandle TrackResource(ref readonly Allocation allocation, bool isTemp)
|
||||||
{
|
{
|
||||||
int id;
|
var id = _allocations.Add(new(in allocation, _renderSystem.CPUFenceValue), out var generation);
|
||||||
uint generation;
|
|
||||||
AllocationInfo allocInfo;
|
|
||||||
|
|
||||||
if (_freeSlots.Count > 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 handle = new ResourceHandle(id, generation);
|
var handle = new ResourceHandle(id, generation);
|
||||||
if (isTemp)
|
if (isTemp)
|
||||||
@@ -217,19 +189,6 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
return new(handle);
|
return new(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public BufferHandle CreateUploadBuffer(uint sizeInBytes, bool tempResource = false)
|
|
||||||
{
|
|
||||||
var desc = new BufferDesc
|
|
||||||
{
|
|
||||||
Size = sizeInBytes,
|
|
||||||
Usage = BufferUsage.Upload,
|
|
||||||
MemoryType = MemoryType.Upload
|
|
||||||
};
|
|
||||||
|
|
||||||
return CreateBufferHandle(in desc, tempResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public IRenderTarget CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false)
|
public IRenderTarget CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false)
|
||||||
{
|
{
|
||||||
@@ -246,7 +205,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public IBuffer CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false)
|
public IBuffer CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false)
|
||||||
{
|
{
|
||||||
return new D3D12Buffer(CreateBufferHandle(in desc, tempResource), in desc);
|
return new D3D12Buffer(CreateBufferHandle(in desc, tempResource), in desc, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Conversion Methods
|
#region Conversion Methods
|
||||||
@@ -367,9 +326,9 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
while (_temResources.Count > 0)
|
while (_temResources.Count > 0)
|
||||||
{
|
{
|
||||||
var handle = _temResources.Peek();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -386,13 +345,13 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
throw new InvalidOperationException("Invalid resource handle.");
|
throw new InvalidOperationException("Invalid resource handle.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var allocationInfo = ref _allocations[handle.id];
|
var info = _allocations.GetElementAt(handle.id, handle.generation);
|
||||||
if (!allocationInfo.Allocated || allocationInfo.generation != handle.generation)
|
if (!info.Allocated)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Resource with ID {handle.id} and generation {handle.generation} is not allocated or has been released.");
|
throw new InvalidOperationException($"Resource with ID {handle.id} and generation {handle.generation} is not allocated or has been released.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocationInfo.allocation.Resource;
|
return info.allocation.Resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseResource(ResourceHandle handle)
|
public void ReleaseResource(ResourceHandle handle)
|
||||||
@@ -402,15 +361,15 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var allocationInfo = ref _allocations[handle.id];
|
ref var info = ref _allocations.GetElementReferenceAt(handle.id, handle.generation, out var exist);
|
||||||
|
|
||||||
if (!allocationInfo.Allocated || allocationInfo.generation != handle.generation)
|
if (!exist || !info.Allocated)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocationInfo.Dispose();
|
info.Dispose();
|
||||||
_freeSlots.Enqueue(handle.id);
|
_allocations.Remove(handle.id, handle.generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -421,9 +380,9 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator<ID3D12Resource
|
|||||||
throw new InvalidOperationException($"ResourceAllocator is being disposed with {_allocations.Count} allocations still registered. Ensure all resources are released before disposing.");
|
throw new InvalidOperationException($"ResourceAllocator is being disposed with {_allocations.Count} allocations still registered. Ensure all resources are released before disposing.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for (var i = 0; i < _allocations.Count; i++)
|
foreach (var info in _allocations)
|
||||||
{
|
{
|
||||||
_allocations[i].Dispose();
|
info.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_allocations.Dispose();
|
_allocations.Dispose();
|
||||||
|
|||||||
11
Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs
Normal file
11
Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
|
internal class D3D12ResourceDatabase
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -10,11 +10,11 @@ internal unsafe static class D3D12PipelineResource
|
|||||||
public const int BACK_BUFFER_COUNT = 2;
|
public const int BACK_BUFFER_COUNT = 2;
|
||||||
|
|
||||||
private readonly static InputElementDescription[] s_inputElementDescs = [
|
private readonly static InputElementDescription[] s_inputElementDescs = [
|
||||||
new InputElementDescription{ SemanticName = Vertex.Semantic.PositionName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
new InputElementDescription{ SemanticName = Vertex.Semantic.pPositionName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
||||||
new InputElementDescription{ SemanticName = Vertex.Semantic.NormalName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
new InputElementDescription{ SemanticName = Vertex.Semantic.pNormalName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
||||||
new InputElementDescription{ SemanticName = Vertex.Semantic.TangentName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
new InputElementDescription{ SemanticName = Vertex.Semantic.pTangentName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
||||||
new InputElementDescription{ SemanticName = Vertex.Semantic.ColorName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
new InputElementDescription{ SemanticName = Vertex.Semantic.pColorName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 },
|
||||||
new InputElementDescription{ SemanticName = Vertex.Semantic.UVName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 }
|
new InputElementDescription{ SemanticName = Vertex.Semantic.pUVName, SemanticIndex = 0u, Format = Format.R32G32B32A32Float, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = InputClassification.PerVertexData, InstanceDataStepRate = 0 }
|
||||||
];
|
];
|
||||||
|
|
||||||
public const Format SWAP_CHAIN_BACK_BUFFER_FORMAT = Format.B8G8R8A8Unorm;
|
public const Format SWAP_CHAIN_BACK_BUFFER_FORMAT = Format.B8G8R8A8Unorm;
|
||||||
|
|||||||
@@ -1,251 +0,0 @@
|
|||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
|
||||||
|
|
||||||
public struct Bounds : IEquatable<Bounds>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum point contained by the AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If any component of <see cref="Min"/> is greater than <see cref="Max"/> then this AABB is invalid.
|
|
||||||
/// </remarks>
|
|
||||||
/// <seealso cref="IsValid"/>
|
|
||||||
public Vector3 Min
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum point contained by the AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If any component of <see cref="Max"/> is less than <see cref="Min"/> then this AABB is invalid.
|
|
||||||
/// </remarks>
|
|
||||||
/// <seealso cref="IsValid"/>
|
|
||||||
public Vector3 Max
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs the AABB with the given minimum and maximum.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If you have a center and extents, you can call <see cref="CreateFromCenterAndExtents"/> or <see cref="CreateFromCenterAndHalfExtents"/>
|
|
||||||
/// to create the AABB.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="min">Minimum point inside AABB.</param>
|
|
||||||
/// <param name="max">Maximum point inside AABB.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public Bounds(Vector3 min, Vector3 max)
|
|
||||||
{
|
|
||||||
Min = min;
|
|
||||||
Max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the AABB from a center and extents.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This function takes full extents. It is the distance between <see cref="Min"/> and <see cref="Max"/>.
|
|
||||||
/// If you have half extents, you can call <see cref="CreateFromCenterAndHalfExtents"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="center">Center of AABB.</param>
|
|
||||||
/// <param name="extents">Full extents of AABB.</param>
|
|
||||||
/// <returns>AABB created from inputs.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Bounds CreateFromCenterAndExtents(Vector3 center, Vector3 extents)
|
|
||||||
{
|
|
||||||
return CreateFromCenterAndHalfExtents(center, extents * 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the AABB from a center and half extents.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This function takes half extents. It is half the distance between <see cref="Min"/> and <see cref="Max"/>.
|
|
||||||
/// If you have full extents, you can call <see cref="CreateFromCenterAndExtents"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="center">Center of AABB.</param>
|
|
||||||
/// <param name="halfExtents">Half extents of AABB.</param>
|
|
||||||
/// <returns>AABB created from inputs.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Bounds CreateFromCenterAndHalfExtents(Vector3 center, Vector3 halfExtents)
|
|
||||||
{
|
|
||||||
return new Bounds(center - halfExtents, center + halfExtents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new AABB with zero extents, centered at the origin.
|
|
||||||
/// </summary>
|
|
||||||
public static Bounds Zero
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new Bounds(Vector3.Zero, Vector3.Zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the extents of the AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Extents is the componentwise distance between min and max.
|
|
||||||
/// </remarks>
|
|
||||||
public readonly Vector3 Extents => Max - Min;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the half extents of the AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// HalfExtents is half of the componentwise distance between min and max. Subtracting HalfExtents from Center
|
|
||||||
/// gives Min and adding HalfExtents to Center gives Max.
|
|
||||||
/// </remarks>
|
|
||||||
public readonly Vector3 HalfExtents => (Max - Min) * 0.5f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the center of the AABB.
|
|
||||||
/// </summary>
|
|
||||||
public readonly Vector3 Center => (Max + Min) * 0.5f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if the AABB is valid.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// An AABB is considered valid if <see cref="Min"/> is componentwise less than or equal to <see cref="Max"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>True if <see cref="Min"/> is componentwise less than or equal to <see cref="Max"/>.</returns>
|
|
||||||
public readonly bool IsValid => Vector3.Dot(Min, Min) <= Vector3.Dot(Max, Max);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Computes the surface area for this axis aligned bounding box.
|
|
||||||
/// </summary>
|
|
||||||
public readonly float SurfaceArea
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var diff = Max - Min;
|
|
||||||
return 2 * Vector3.Dot(diff, new Vector3(diff.Y, diff.Z, diff.X));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests if the input point is contained by the AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">Point to test.</param>
|
|
||||||
/// <returns>True if AABB contains the input point.</returns>
|
|
||||||
[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);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests if the input AABB is contained entirely by this AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="aabb">AABB to test.</param>
|
|
||||||
/// <returns>True if input AABB is contained entirely by this AABB.</returns>
|
|
||||||
[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);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests if the input AABB overlaps this AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="aabb">AABB to test.</param>
|
|
||||||
/// <returns>True if input AABB overlaps with this AABB.</returns>
|
|
||||||
[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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Expands the AABB by the given signed distance.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Positive distance expands the AABB while negative distance shrinks the AABB.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="signedDistance">Signed distance to expand the AABB with.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Expand(float signedDistance)
|
|
||||||
{
|
|
||||||
Min -= new Vector3(signedDistance);
|
|
||||||
Max += new Vector3(signedDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encapsulates the given AABB.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// 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.
|
|
||||||
/// </remarks>
|
|
||||||
/// <seealso cref="Contains(Unity.Mathematics.Geometry.MinMaxAABB)"/>
|
|
||||||
/// <param name="aabb">AABB to encapsulate.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Encapsulate(Bounds aabb)
|
|
||||||
{
|
|
||||||
Min = Vector3.Min(Min, aabb.Min);
|
|
||||||
Max = Vector3.Max(Max, aabb.Max);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encapsulate the given point.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// 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.
|
|
||||||
/// </remarks>
|
|
||||||
/// <seealso cref="Contains(Unity.Mathematics.float3)"/>
|
|
||||||
/// <param name="point">Point to encapsulate.</param>
|
|
||||||
[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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,17 +4,17 @@ using System.Runtime.InteropServices;
|
|||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a color with 32-bit components."/>
|
/// Represents a color with 4 bytes components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 4)]
|
[StructLayout(LayoutKind.Sequential, Size = 4)]
|
||||||
public struct Color32 : IEquatable<Color32>
|
public struct Color4 : IEquatable<Color4>
|
||||||
{
|
{
|
||||||
public byte r;
|
public byte r;
|
||||||
public byte g;
|
public byte g;
|
||||||
public byte b;
|
public byte b;
|
||||||
public byte a;
|
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.r = r;
|
||||||
this.g = g;
|
this.g = g;
|
||||||
@@ -22,24 +22,24 @@ public struct Color32 : IEquatable<Color32>
|
|||||||
this.a = a;
|
this.a = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color32(Color color)
|
public Color4(Color color)
|
||||||
: this(color.R, color.G, color.B, color.A)
|
: 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))
|
: 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;
|
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override readonly bool Equals(object? obj)
|
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()
|
public override readonly int GetHashCode()
|
||||||
@@ -47,29 +47,29 @@ public struct Color32 : IEquatable<Color32>
|
|||||||
return HashCode.Combine(r, g, b, a);
|
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);
|
return left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator !=(Color32 left, Color32 right)
|
public static bool operator !=(Color4 left, Color4 right)
|
||||||
{
|
{
|
||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a color with 128-bit components.
|
/// Represents a color with 16 bytes components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||||
public struct Color128 : IEquatable<Color128>
|
public struct Color16 : IEquatable<Color16>
|
||||||
{
|
{
|
||||||
public float r;
|
public float r;
|
||||||
public float g;
|
public float g;
|
||||||
public float b;
|
public float b;
|
||||||
public float a;
|
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.r = r;
|
||||||
this.g = g;
|
this.g = g;
|
||||||
@@ -77,24 +77,24 @@ public struct Color128 : IEquatable<Color128>
|
|||||||
this.a = a;
|
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)
|
: 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)
|
: 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);
|
return r.Equals(other.r) && g.Equals(other.g) && b.Equals(other.b) && a.Equals(other.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override readonly bool Equals(object? obj)
|
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()
|
public readonly override int GetHashCode()
|
||||||
@@ -102,12 +102,12 @@ public struct Color128 : IEquatable<Color128>
|
|||||||
return HashCode.Combine(r, g, b, a);
|
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);
|
return left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator !=(Color128 left, Color128 right)
|
public static bool operator !=(Color16 left, Color16 right)
|
||||||
{
|
{
|
||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
|
|||||||
54
Ghost.Graphics/Data/GraphicsResourceManager.cs
Normal file
54
Ghost.Graphics/Data/GraphicsResourceManager.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
|
public struct BatchMaterialID : IEquatable<BatchMaterialID>
|
||||||
|
{
|
||||||
|
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<BatchMaterialID, Material> _materials = new();
|
||||||
|
private readonly Dictionary<BatchMeshID, MeshHandle> _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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using Ghost.Graphics.RHI;
|
|||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||||
|
using Misaki.HighPerformance.Mathematics.Geometry;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Win32.Graphics.Direct3D12;
|
using Win32.Graphics.Direct3D12;
|
||||||
@@ -10,19 +11,85 @@ using Win32.Graphics.Dxgi.Common;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CPU-side mesh data structure.
|
||||||
|
/// </summary>
|
||||||
|
public struct MeshData
|
||||||
|
{
|
||||||
|
public UnsafeList<Vertex> vertices;
|
||||||
|
public UnsafeList<int> indices;
|
||||||
|
public AABB boundingBox;
|
||||||
|
public MeshHandle handle;
|
||||||
|
|
||||||
|
public MeshData()
|
||||||
|
{
|
||||||
|
handle = MeshHandle.Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GPU-side mesh handle containing buffer references.
|
||||||
|
/// </summary>
|
||||||
|
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<BatchMeshID>
|
||||||
|
{
|
||||||
|
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
|
public unsafe sealed class Mesh : IDisposable
|
||||||
{
|
{
|
||||||
private UnsafeList<Vertex> _vertices;
|
private UnsafeList<Vertex> _vertices;
|
||||||
private UnsafeList<int> _indices;
|
private UnsafeList<int> _indices;
|
||||||
|
|
||||||
private Bounds _boundingBox;
|
private AABB _boundingBox;
|
||||||
|
|
||||||
private IBuffer? _vertexBuffer;
|
private IBuffer? _vertexBuffer;
|
||||||
private IBuffer? _indexBuffer;
|
private IBuffer? _indexBuffer;
|
||||||
|
|
||||||
public Span<Vertex> Vertices => _vertices.AsSpan();
|
public Span<Vertex> Vertices => _vertices.AsSpan();
|
||||||
public Span<int> Indices => _indices.AsSpan();
|
public Span<int> Indices => _indices.AsSpan();
|
||||||
public Bounds BoundingBox => _boundingBox;
|
public AABB BoundingBox => _boundingBox;
|
||||||
|
|
||||||
public uint VertexCount => (uint)_vertices.Count;
|
public uint VertexCount => (uint)_vertices.Count;
|
||||||
public uint IndexCount => (uint)_indices.Count;
|
public uint IndexCount => (uint)_indices.Count;
|
||||||
@@ -296,62 +363,6 @@ public unsafe sealed class Mesh : IDisposable
|
|||||||
CreateBindlessDescriptors();
|
CreateBindlessDescriptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates SRVs for vertex and index buffers in the bindless descriptor heap
|
|
||||||
/// </summary>
|
|
||||||
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()
|
internal void MarkNoLongerReadable()
|
||||||
{
|
{
|
||||||
_vertices.Dispose();
|
_vertices.Dispose();
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public unsafe class RenderTexture : Texture
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="commandList">Command list to record clear commands</param>
|
/// <param name="commandList">Command list to record clear commands</param>
|
||||||
/// <param name="clearColor">Color to clear to</param>
|
/// <param name="clearColor">Color to clear to</param>
|
||||||
public void ClearColor(CommandList commandList, Color128 clearColor)
|
public void ClearColor(CommandList commandList, Color16 clearColor)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ public readonly struct ResourceHandle : IEquatable<ResourceHandle>
|
|||||||
private const int _INVALID_ID = -1;
|
private const int _INVALID_ID = -1;
|
||||||
|
|
||||||
public readonly int id;
|
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.id = id;
|
||||||
this.generation = generation;
|
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)
|
public bool Equals(ResourceHandle other)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Numerics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -7,7 +7,7 @@ using Win32.Graphics.Dxgi.Common;
|
|||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Data;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct Vertex(Vector4 position, Vector4 normal, Vector4 tangent, Color128 color, Vector4 uv)
|
public struct Vertex
|
||||||
{
|
{
|
||||||
public unsafe struct Semantic
|
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_colorBytes = Encoding.UTF8.GetBytes("COLOR");
|
||||||
private static readonly byte[] s_uvBytes = Encoding.UTF8.GetBytes("TEXCOORD");
|
private static readonly byte[] s_uvBytes = Encoding.UTF8.GetBytes("TEXCOORD");
|
||||||
|
|
||||||
public static byte* PositionName => (byte*)Unsafe.AsPointer(ref s_positionBytes[0]);
|
public static byte* pPositionName => (byte*)Unsafe.AsPointer(ref s_positionBytes[0]);
|
||||||
public static byte* NormalName => (byte*)Unsafe.AsPointer(ref s_normalBytes[0]);
|
public static byte* pNormalName => (byte*)Unsafe.AsPointer(ref s_normalBytes[0]);
|
||||||
public static byte* TangentName => (byte*)Unsafe.AsPointer(ref s_tangentBytes[0]);
|
public static byte* pTangentName => (byte*)Unsafe.AsPointer(ref s_tangentBytes[0]);
|
||||||
public static byte* ColorName => (byte*)Unsafe.AsPointer(ref s_colorBytes[0]);
|
public static byte* pColorName => (byte*)Unsafe.AsPointer(ref s_colorBytes[0]);
|
||||||
public static byte* UVName => (byte*)Unsafe.AsPointer(ref s_uvBytes[0]);
|
public static byte* pUVName => (byte*)Unsafe.AsPointer(ref s_uvBytes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector4 Position
|
public float4 Position
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = position;
|
}
|
||||||
|
|
||||||
public Vector4 Normal
|
public float4 Normal
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = normal;
|
}
|
||||||
|
|
||||||
public Vector4 Tangent
|
public float4 Tangent
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = tangent;
|
}
|
||||||
|
|
||||||
public Color128 Color
|
public Color16 Color
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = color;
|
}
|
||||||
|
|
||||||
public Vector4 UV
|
public float4 UV
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
} = uv;
|
}
|
||||||
|
|
||||||
|
public Vertex(float4 position, float4 normal, float4 tangent, Color16 color, float4 uv)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Normal = normal;
|
||||||
|
Tangent = tangent;
|
||||||
|
Color = color;
|
||||||
|
UV = uv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!--<PackageReference Include="StbImageSharp" Version="2.30.15" />-->
|
<!--<PackageReference Include="StbImageSharp" Version="2.30.15" />-->
|
||||||
|
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.1.0" />
|
||||||
<PackageReference Include="Vortice.Dxc.Native" Version="1.0.3" />
|
<PackageReference Include="Vortice.Dxc.Native" Version="1.0.3" />
|
||||||
<PackageReference Include="Vortice.Win32.Graphics.D3D12MemoryAllocator" Version="2.2.7" />
|
<PackageReference Include="Vortice.Win32.Graphics.D3D12MemoryAllocator" Version="2.2.7" />
|
||||||
<PackageReference Include="Vortice.Win32.Graphics.Direct3D.Dxc" Version="2.2.7" />
|
<PackageReference Include="Vortice.Win32.Graphics.Direct3D.Dxc" Version="2.2.7" />
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="renderTarget">Render target to render into</param>
|
/// <param name="renderTarget">Render target to render into</param>
|
||||||
/// <param name="clearColor">Color to clear the render target with</param>
|
/// <param name="clearColor">Color to clear the render target with</param>
|
||||||
public void BeginRenderPass(IRenderTarget renderTarget, Color128 clearColor);
|
public void BeginRenderPass(IRenderTarget renderTarget, Color16 clearColor);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ends the current render pass
|
/// Ends the current render pass
|
||||||
|
|||||||
@@ -44,16 +44,4 @@ public interface IResourceAllocator
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handle">Resource handle</param>
|
/// <param name="handle">Resource handle</param>
|
||||||
public void ReleaseResource(ResourceHandle handle);
|
public void ReleaseResource(ResourceHandle handle);
|
||||||
}
|
|
||||||
|
|
||||||
internal interface IResourceAllocator<T> : IResourceAllocator
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Get the raw gpu resource pointer from a resource handle
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the resource.</typeparam>
|
|
||||||
/// <param name="handle">Resource handle</param>
|
|
||||||
/// <returns>Pointer to the resource</returns>
|
|
||||||
public unsafe T* GetResource(ResourceHandle handle);
|
|
||||||
}
|
}
|
||||||
35
Ghost.Graphics/RHI/IResourceDatabase.cs
Normal file
35
Ghost.Graphics/RHI/IResourceDatabase.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Ghost.Graphics.Data;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
public interface IResourceDatabase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get the raw gpu resource pointer from a resource handle
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the resource.</typeparam>
|
||||||
|
/// <param name="handle">Resource handle</param>
|
||||||
|
/// <returns>Pointer to the resource</returns>
|
||||||
|
public unsafe T* GetResource<T>(ResourceHandle handle)
|
||||||
|
where T: unmanaged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the current state of the specified resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle that uniquely identifies the resource whose state is to be retrieved. Must not be null.</param>
|
||||||
|
/// <returns>A ResourceState value representing the current state of the resource associated with the specified handle.</returns>
|
||||||
|
public ResourceState GetResourceState(ResourceHandle handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the state of the specified resource handle to the given value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle that identifies the resource whose state will be updated. Cannot be null.</param>
|
||||||
|
/// <param name="state">The new state to assign to the resource represented by <paramref name="handle"/>.</param>
|
||||||
|
public void SetResourceState(ResourceHandle handle, ResourceState state);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a resource from the database using its handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the resource to be removed.</param>
|
||||||
|
public void RemoveResource(ResourceHandle handle);
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ public static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a unit cube centered at the origin with size 1.
|
/// Creates a unit cube centered at the origin with size 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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 half = size * 0.5f;
|
||||||
var mesh = new Mesh(24, 36);
|
var mesh = new Mesh(24, 36);
|
||||||
@@ -61,7 +61,7 @@ public static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a plane on the XZ axis centered at the origin.
|
/// Creates a plane on the XZ axis centered at the origin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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 hw = width * 0.5f;
|
||||||
var hd = depth * 0.5f;
|
var hd = depth * 0.5f;
|
||||||
@@ -83,7 +83,7 @@ public static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a UV sphere centered at the origin.
|
/// Creates a UV sphere centered at the origin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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);
|
var mesh = new Mesh((latitudeSegments + 1) * (longitudeSegments + 1), latitudeSegments * longitudeSegments * 6);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user