Continue working on RHI

This commit is contained in:
2025-09-12 21:44:32 +09:00
parent 1b0ef03728
commit 1dfed83e38
49 changed files with 1780 additions and 2195 deletions

View File

@@ -0,0 +1,46 @@
using Ghost.Graphics.D3D12;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Helpers;
using System.Runtime.CompilerServices;
namespace Ghost.Graphics.Data;
internal struct CBufferCache : IDisposable
{
public UnsafeArray<byte> CpuData
{
get;
set;
}
public GraphicsBuffer GpuResource
{
get;
}
private readonly uint _alignedSize;
internal unsafe CBufferCache(uint bufferSize)
{
_alignedSize = (bufferSize + 255u) & ~255u;
CpuData = new((int)_alignedSize, Allocator.Persistent);
GpuResource = GraphicsBuffer.Create(_alignedSize, GraphicsBuffer.Usage.Constant);
GpuResource.Name = "Material_CBufferCache";
UploadToGpu();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void UploadToGpu()
{
GpuResource.SetData(CpuData.AsSpan(), 0);
}
public readonly void Dispose()
{
CpuData.Dispose();
GpuResource.Dispose();
}
}

View File

@@ -1,5 +1,5 @@
using Ghost.Graphics.D3D12;
using Ghost.Graphics.Shading;
using Ghost.Graphics.RHI;
using System.Numerics;
using System.Runtime.CompilerServices;
using Win32.Graphics.Direct3D12;
@@ -12,10 +12,11 @@ namespace Ghost.Graphics.Data;
public unsafe class Material : IDisposable
{
private readonly CBufferCache[] _cbufferCaches;
private readonly List<Texture2D> _textures = new();
private bool _disposed;
internal ReadOnlySpan<CBufferCache> CBufferCaches => _cbufferCaches;
public Shader Shader
{
get; set;
@@ -129,23 +130,12 @@ public unsafe class Material : IDisposable
SetMatrix(Shader.GetPropertyId(propertyName), in value);
}
/// <summary>
/// Adds a bindless texture to the material and returns its index
/// </summary>
/// <param name="texture">The bindless texture to add</param>
/// <returns>The index of the texture in the material's texture list</returns>
public int AddTexture(Texture2D texture)
{
_textures.Add(texture);
return _textures.Count - 1;
}
/// <summary>
/// Sets a texture index for a shader property (for bindless texture access)
/// </summary>
/// <param name="propertyName">The name of the shader property (e.g., "_TextureIndex1")</param>
/// <param name="texture">The bindless texture to reference</param>
public void SetTextureIndex(string propertyName, Texture2D texture)
public void SetTexture(string propertyName, Texture2D texture)
{
SetUInt(propertyName, texture.DescriptorIndex);
}
@@ -156,18 +146,14 @@ public unsafe class Material : IDisposable
/// <param name="mesh">The mesh whose buffer indices to set</param>
/// <param name="vertexBufferIndexProperty">The name of the vertex buffer index property (e.g., "_VertexBufferIndex")</param>
/// <param name="indexBufferIndexProperty">The name of the index buffer index property (e.g., "_IndexBufferIndex")</param>
public void SetMeshBufferIndices(Mesh mesh, string vertexBufferIndexProperty = "_VertexBufferIndex", string indexBufferIndexProperty = "_IndexBufferIndex")
public void SetMeshBuffer(Mesh mesh, string vertexBufferIndexProperty = "_VertexBufferIndex", string indexBufferIndexProperty = "_IndexBufferIndex")
{
SetUInt(vertexBufferIndexProperty, mesh.VertexBufferDescriptorIndex);
SetUInt(indexBufferIndexProperty, mesh.IndexBufferDescriptorIndex);
}
/// <summary>
/// Gets all textures used by this material
/// </summary>
public IReadOnlyList<Texture2D> Textures => _textures;
private unsafe void WriteToCache<T>(int propertyId, in T value) where T : unmanaged
private unsafe void WriteToCache<T>(int propertyId, in T value)
where T : unmanaged
{
if (propertyId == -1)
{
@@ -177,7 +163,7 @@ public unsafe class Material : IDisposable
var propInfo = Shader.Properties[propertyId];
if (propInfo.Size != sizeof(T))
{
throw new ArgumentException($"Property '{propInfo.Name}' has a size mismatch. Expected {sizeof(T)} bytes, but got {propInfo.Size} bytes.");
throw new ArgumentException($"Property '{propInfo.Name}' has a size mismatch. Expected {propInfo.Size} bytes, but got {sizeof(T)} bytes.");
}
var cache = _cbufferCaches[propInfo.CBufferIndex];
@@ -196,37 +182,6 @@ public unsafe class Material : IDisposable
}
}
/// <summary>
/// Binds the material for bindless rendering
/// </summary>
/// <param name="cmd">Command list to bind to</param>
internal void Bind(CommandList cmd)
{
var commandList = cmd.NativeCommandList.Ptr;
// Set root signature and pipeline state
commandList->SetGraphicsRootSignature(Shader.RootSignature);
commandList->SetPipelineState(Shader.PipelineState);
// Set descriptor heaps - CRUCIAL: Use the specialized bindless heap for SM 6.6
var heaps = stackalloc ID3D12DescriptorHeap*[2];
heaps[0] = GraphicsPipeline.DescriptorAllocator.GetBindlessHeap().Ptr; // Specialized bindless heap
heaps[1] = Shader.SamplerHeap.Ptr; // Sampler heap from shader
commandList->SetDescriptorHeaps(2, heaps);
// Bind constant buffers
var rootParamIndex = 0u;
foreach (var cbufferInfo in Shader.ConstantBuffers)
{
var cache = _cbufferCaches[cbufferInfo.RegisterSlot];
commandList->SetGraphicsRootConstantBufferView(rootParamIndex++, cache.GpuResource.GPUAddress);
}
// Bind sampler descriptor table (last root parameter)
var samplerGpuHandle = Shader.SamplerHeap.Ptr->GetGPUDescriptorHandleForHeapStart();
commandList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
}
public void Dispose()
{
if (_disposed)

View File

@@ -3,7 +3,7 @@ using Win32.Graphics.D3D12MemoryAllocator;
namespace Ghost.Graphics.Data;
internal readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
public readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposable
{
private const int _INVALID_ID = -1;
@@ -28,7 +28,7 @@ internal readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposabl
throw new InvalidOperationException("Cannot get allocation from an invalid AllocationHandle.");
}
return GraphicsPipeline.ResourceAllocator.GetAllocation(this);
return GraphicsPipeline.ResourceAllocator.GetResource(this);
}
public bool Equals(ResourceHandle other)
@@ -51,7 +51,7 @@ internal readonly struct ResourceHandle : IEquatable<ResourceHandle>, IDisposabl
public void Dispose()
{
GraphicsPipeline.ResourceAllocator.ReleaseAllocation(this);
GraphicsPipeline.ResourceAllocator.ReleaseResource(this);
}
public static implicit operator Allocation(ResourceHandle handle)
@@ -79,8 +79,7 @@ public readonly struct TextureHandle : IEquatable<TextureHandle>, IDisposable
{
private readonly ResourceHandle _resourceHandle;
internal ResourceHandle ResourceHandle => _resourceHandle;
public ResourceHandle ResourceHandle => _resourceHandle;
public static TextureHandle Invalid => new(ResourceHandle.Invalid);
internal TextureHandle(ResourceHandle resourceHandle)
@@ -125,8 +124,7 @@ public readonly struct BufferHandle : IEquatable<BufferHandle>, IDisposable
{
private readonly ResourceHandle _resourceHandle;
internal ResourceHandle ResourceHandle => _resourceHandle;
public ResourceHandle ResourceHandle => _resourceHandle;
public static BufferHandle Invalid => new(ResourceHandle.Invalid);
internal BufferHandle(ResourceHandle resourceHandle)

View File

@@ -0,0 +1,116 @@
namespace Ghost.Graphics.Data;
internal readonly struct TextureInfo
{
public required string Name
{
get; init;
}
public uint RegisterSlot
{
get; init;
}
public uint RootParameterIndex
{
get; init;
}
}
internal readonly struct PropertyInfo
{
public required string Name
{
get; init;
}
public uint CBufferIndex
{
get; init;
}
public uint ByteOffset
{
get; init;
}
public uint Size
{
get; init;
}
}
internal readonly struct CBufferInfo
{
public required string Name
{
get; init;
}
public uint Size
{
get; init;
}
public uint RegisterSlot
{
get; init;
}
}
/// <summary>
/// Bindless shader implementation using SM 6.6 with ResourceDescriptorHeap
/// and D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED
/// Enhanced to support both bindless and regular texture binding for hybrid materials
/// </summary>
public unsafe class Shader : IDisposable
{
private readonly string _source;
private readonly List<CBufferInfo> _constantBuffers = new();
private readonly List<PropertyInfo> _properties = new();
private readonly List<TextureInfo> _regularTextures = new(); // Add regular texture support
private readonly Dictionary<string, int> _propertyNameToIdMap = new();
private bool _disposed;
internal string Source => _source;
internal List<CBufferInfo> ConstantBuffers => _constantBuffers;
internal List<PropertyInfo> Properties => _properties;
internal List<TextureInfo> RegularTextures => _regularTextures;
internal Dictionary<string, int> PropertyNameToIdMap => _propertyNameToIdMap;
internal Shader(string shaderCode)
{
_source = shaderCode;
}
/// <summary>
/// Gets a unique, stable ID for a shader property.
/// </summary>
/// <param name="propertyName">The name of the property (e.g., "_Color").</param>
/// <returns>The integer ID of the property, or -1 if not found.</returns>
public int GetPropertyId(string propertyName)
{
return _propertyNameToIdMap.TryGetValue(propertyName, out var id) ? id : -1;
}
public void Dispose()
{
if (_disposed)
{
return;
}
_constantBuffers.Clear();
_properties.Clear();
_propertyNameToIdMap.Clear();
_regularTextures.Clear();
GC.SuppressFinalize(this);
_disposed = true;
}
}