forked from Misaki/GhostEngine
Continue working on RHI
This commit is contained in:
46
Ghost.Graphics/Data/CBufferCache.cs
Normal file
46
Ghost.Graphics/Data/CBufferCache.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
116
Ghost.Graphics/Data/Shader.cs
Normal file
116
Ghost.Graphics/Data/Shader.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user