Refactor graphics engine dependencies and structure
Removed references to `Misaki.HighPerformance.Unsafe` and replaced them with `Misaki.HighPerformance.LowLevel` in multiple files. Removed calls to `AllocationManager.Initialize()` and `AllocationManager.Dispose()` in `EngineCore.cs`. Added new methods to the `ICommandBuffer` interface for enhanced rendering capabilities. Updated the `D3D12CommandBuffer` class to implement new graphics command handling methods. Added the `Material` class to manage shader properties and caching for improved performance. Encapsulated shader compilation and reflection processes within the `Shader` class for better organization. Added the `CBufferCache` struct to optimize GPU resource management for constant buffer data. Updated the `MeshRenderPass` class to utilize the new `Material` class for dynamic mesh rendering. Updated various project files to reflect the restructuring of dependencies. Modified XAML files and code-behind for improved readability and maintainability.
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
using Ghost.Engine.Services;
|
||||
using Ghost.Graphics;
|
||||
using Ghost.Graphics.Data;
|
||||
using Misaki.HighPerformance.Unsafe.Buffer;
|
||||
|
||||
namespace Ghost.Engine;
|
||||
|
||||
@@ -12,8 +11,6 @@ internal class EngineCore
|
||||
{
|
||||
ActivationHandler.Handle(args);
|
||||
|
||||
AllocationManager.Initialize();
|
||||
|
||||
GraphicsPipeline.Initialize(GraphicsAPI.D3D12);
|
||||
GraphicsPipeline.Start();
|
||||
|
||||
@@ -29,6 +26,5 @@ internal class EngineCore
|
||||
{
|
||||
GraphicsPipeline.SignalCPUReady();
|
||||
GraphicsPipeline.Shutdown();
|
||||
AllocationManager.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll</HintPath>
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Ghost.Core;
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll</HintPath>
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Ghost.Core;
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Ghost.Entities.Query;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Query;
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Query;
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ namespace Ghost.Graphics.Contracts;
|
||||
|
||||
public interface ICommandBuffer
|
||||
{
|
||||
public void DrawMesh(Mesh mesh);
|
||||
public void CopyResource(IResource dstResource, uint dstOffset, IResource srcResource, uint srcOffset, uint size);
|
||||
// TODO: They should be internal, maybe an interface ICommandBufferInternal?
|
||||
public void BarrierTransition(IResource resource, ResourceStates beforeState, ResourceStates afterState);
|
||||
public void SetGraphicsRootConstantBufferView(uint slot, ulong gpuAddress);
|
||||
|
||||
public void DrawMesh(Mesh mesh, Material material);
|
||||
public void CopyResource(IResource dstResource, uint dstOffset, IResource srcResource, uint srcOffset, uint size);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Ghost.Graphics.Contracts;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
public interface IResource : IDisposable
|
||||
namespace Ghost.Graphics.Contracts;
|
||||
|
||||
public unsafe interface IResource : IDisposable
|
||||
{
|
||||
public ulong GPUAddress
|
||||
{
|
||||
@@ -20,4 +22,17 @@ public interface IResource : IDisposable
|
||||
|
||||
public void SetData<T>(Span<T> data)
|
||||
where T : unmanaged;
|
||||
|
||||
public void SetData<T>(T* data, uint length)
|
||||
where T : unmanaged;
|
||||
|
||||
public void SetData(void* data, uint size);
|
||||
|
||||
public UnsafeArray<T> ReadData<T>(Allocator allocator)
|
||||
where T : unmanaged;
|
||||
|
||||
public void ReadData<T>(T* ppData, uint* size)
|
||||
where T : unmanaged;
|
||||
|
||||
public void ReadData(void* ppData, uint* size);
|
||||
}
|
||||
@@ -17,8 +17,24 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
_commandList = commandList;
|
||||
}
|
||||
|
||||
public void DrawMesh(Mesh mesh)
|
||||
public void BarrierTransition(IResource resource, ResourceStates beforeState, ResourceStates afterState)
|
||||
{
|
||||
var dxResource = (D3D12Resource)resource;
|
||||
_commandList.Ptr->ResourceBarrierTransition(dxResource.NativeResource.Ptr, beforeState, afterState);
|
||||
}
|
||||
|
||||
public void SetGraphicsRootConstantBufferView(uint slot, ulong gpuAddress)
|
||||
{
|
||||
_commandList.Ptr->SetGraphicsRootConstantBufferView(slot, gpuAddress);
|
||||
}
|
||||
|
||||
public void DrawMesh(Mesh mesh, Material material)
|
||||
{
|
||||
_commandList.Ptr->SetGraphicsRootSignature(material.Shader.RootSignature);
|
||||
_commandList.Ptr->SetPipelineState(material.Shader.PipelineState);
|
||||
|
||||
material.UploadAndBind(this);
|
||||
|
||||
_commandList.Ptr->IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
|
||||
_commandList.Ptr->IASetVertexBuffers(0, 1, mesh.VertexBufferView);
|
||||
_commandList.Ptr->IASetIndexBuffer(mesh.IndexBufferView);
|
||||
@@ -33,10 +49,4 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
|
||||
_commandList.Ptr->CopyBufferRegion(dstDXResource.NativeResource, dstOffset, srcDXResource.NativeResource, srcOffset, size);
|
||||
}
|
||||
|
||||
public void BarrierTransition(IResource resource, ResourceStates beforeState, ResourceStates afterState)
|
||||
{
|
||||
var dxResource = (D3D12Resource)resource;
|
||||
_commandList.Ptr->ResourceBarrierTransition(dxResource.NativeResource.Ptr, beforeState, afterState);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
ref var frameResource = ref _frameResources[i];
|
||||
if (frameResource.backBuffer.Get() is not null)
|
||||
{
|
||||
frameResource.backBuffer.Dispose();
|
||||
var c = frameResource.backBuffer.Reset();
|
||||
_rtvHeap.ReleaseDescriptor(frameResource.backBufferDescriptorIndexes);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Win32;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
@@ -8,13 +9,11 @@ namespace Ghost.Graphics.D3D12;
|
||||
|
||||
public unsafe class D3D12Resource : IResource
|
||||
{
|
||||
private ComPtr<ID3D12Resource> _nativeResource
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
private ComPtr<ID3D12Resource> _nativeResource;
|
||||
private string _name = string.Empty;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
internal ConstPtr<ID3D12Resource> NativeResource => new(_nativeResource.Get());
|
||||
|
||||
public ulong GPUAddress => _nativeResource.Get()->GetGPUVirtualAddress();
|
||||
@@ -40,15 +39,34 @@ public unsafe class D3D12Resource : IResource
|
||||
TempResource = temp;
|
||||
}
|
||||
|
||||
~D3D12Resource()
|
||||
{
|
||||
DisposeInternal();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetData<T>(Span<T> data)
|
||||
where T : unmanaged
|
||||
{
|
||||
var size = (uint)(data.Length * sizeof(T));
|
||||
var range = new Win32.Graphics.Direct3D12.Range(0, size);
|
||||
|
||||
fixed (T* ptr = data)
|
||||
{
|
||||
SetData(ptr, (uint)data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void SetData<T>(T* data, uint length)
|
||||
where T : unmanaged
|
||||
{
|
||||
var size = (uint)(length * sizeof(T));
|
||||
SetData((void*)data, size);
|
||||
}
|
||||
|
||||
public unsafe void SetData(void* data, uint size)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var range = new Win32.Graphics.Direct3D12.Range(0, size);
|
||||
|
||||
void* mappedPtr;
|
||||
var hr = _nativeResource.Get()->Map(0, &range, &mappedPtr);
|
||||
if (hr.Failure)
|
||||
@@ -56,14 +74,66 @@ public unsafe class D3D12Resource : IResource
|
||||
var message = hr.ToString();
|
||||
throw new InvalidOperationException($"Failed to map resource: {message}");
|
||||
}
|
||||
Unsafe.CopyBlock(mappedPtr, ptr, size);
|
||||
|
||||
Unsafe.CopyBlock(mappedPtr, data, size);
|
||||
_nativeResource.Get()->Unmap(0, &range);
|
||||
}
|
||||
|
||||
public UnsafeArray<T> ReadData<T>(Allocator allocator)
|
||||
where T : unmanaged
|
||||
{
|
||||
var size = (uint)_nativeResource.Get()->GetDesc().Width;
|
||||
var data = new UnsafeArray<T>((int)(size / (uint)sizeof(T)), allocator);
|
||||
try
|
||||
{
|
||||
ReadData(data.GetUnsafePtr(), &size);
|
||||
return data;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
data.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadData<T>(T* pData, uint* size)
|
||||
where T : unmanaged
|
||||
{
|
||||
ReadData(pData, size);
|
||||
}
|
||||
|
||||
public void ReadData(void* pData, uint* size)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var range = new Win32.Graphics.Direct3D12.Range(0, (uint)_nativeResource.Get()->GetDesc().Width);
|
||||
|
||||
void* mappedPtr;
|
||||
var hr = _nativeResource.Get()->Map(0, &range, &mappedPtr);
|
||||
if (hr.Failure)
|
||||
{
|
||||
var message = hr.ToString();
|
||||
throw new InvalidOperationException($"Failed to map resource: {message}");
|
||||
}
|
||||
|
||||
Unsafe.CopyBlock(pData, mappedPtr, (uint)(range.End - range.Begin));
|
||||
_nativeResource.Get()->Unmap(0, &range);
|
||||
if (size != null)
|
||||
{
|
||||
*size = (uint)(range.End - range.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
internal void DisposeInternal()
|
||||
{
|
||||
var c = _nativeResource.Reset();
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_nativeResource.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -71,6 +141,7 @@ public unsafe class D3D12Resource : IResource
|
||||
if (!TempResource)
|
||||
{
|
||||
DisposeInternal();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,103 @@
|
||||
using Win32;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.Shading;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Graphics.Data;
|
||||
|
||||
public class Material : IDisposable
|
||||
{
|
||||
// TODO: Pipeline state should be abstracted that can support multiple graphics APIs.
|
||||
private ComPtr<ID3D12PipelineState> _pipelineState;
|
||||
private readonly Dictionary<string, CBufferCache> _cbufferCaches;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public Shader Shader
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = Shader.Empty;
|
||||
}
|
||||
|
||||
public Material(Shader shader)
|
||||
{
|
||||
Shader = shader;
|
||||
|
||||
_cbufferCaches = new();
|
||||
foreach (var cbufferInfo in shader.ConstantBuffers.Values)
|
||||
{
|
||||
_cbufferCaches.Add(cbufferInfo.Name, new CBufferCache(cbufferInfo.Size));
|
||||
}
|
||||
}
|
||||
|
||||
~Material()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetFloat(string propertyName, in float value)
|
||||
{
|
||||
WriteToCache(propertyName, in value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetVector(string propertyName, in Vector4 value)
|
||||
{
|
||||
WriteToCache(propertyName, in value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetMatrix(string propertyName, in Matrix4x4 value)
|
||||
{
|
||||
WriteToCache(propertyName, in value);
|
||||
}
|
||||
|
||||
private unsafe void WriteToCache<T>(string propertyName, in T value) where T : unmanaged
|
||||
{
|
||||
if (!Shader.Properties.TryGetValue(propertyName, out var propInfo))
|
||||
{
|
||||
throw new ArgumentException($"Property '{propertyName}' does not exist in the shader.", nameof(propertyName));
|
||||
}
|
||||
|
||||
if (propInfo.Size != sizeof(T))
|
||||
{
|
||||
throw new ArgumentException($"Property '{propertyName}' has a size mismatch. Expected {sizeof(T)} bytes, but got {propInfo.Size} bytes.", nameof(propertyName));
|
||||
}
|
||||
|
||||
var cache = _cbufferCaches[propInfo.CBufferName];
|
||||
|
||||
Unsafe.WriteUnaligned(ref cache.CpuData[(int)propInfo.ByteOffset], value);
|
||||
}
|
||||
|
||||
public void UploadAndBind(ICommandBuffer cmb)
|
||||
{
|
||||
foreach (var cache in _cbufferCaches.Values)
|
||||
{
|
||||
cache.UploadToGpu();
|
||||
}
|
||||
|
||||
foreach (var (name, cache) in _cbufferCaches)
|
||||
{
|
||||
var cbufferInfo = Shader.ConstantBuffers[name];
|
||||
cmb.SetGraphicsRootConstantBufferView(cbufferInfo.RegisterSlot, cache.GpuResource.GPUAddress);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pipelineState.Dispose();
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var cache in _cbufferCaches.Values)
|
||||
{
|
||||
cache.Dispose();
|
||||
}
|
||||
|
||||
_cbufferCaches.Clear();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using Misaki.HighPerformance.Unsafe.Helpers;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.D3D12;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Win32;
|
||||
using Win32.Graphics.Direct3D;
|
||||
using Win32.Graphics.Direct3D.Fxc;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
|
||||
namespace Ghost.Graphics.Data;
|
||||
|
||||
public unsafe class Shader
|
||||
{
|
||||
private static readonly Shader s_empty = new("ErrorShader");
|
||||
public static Shader Empty => s_empty;
|
||||
|
||||
private ComPtr<ID3D12RootSignature> _rootSignature;
|
||||
|
||||
public ConstPtr<ID3D12RootSignature> RootSignature => new(_rootSignature.Get());
|
||||
|
||||
public Shader(string shaderPath)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles HLSL source code from a string into shader bytecode.
|
||||
/// </summary>
|
||||
/// <param name="sourceCode">The string containing the HLSL code.</param>
|
||||
/// <param name="entryPoint">The name of the shader entry point function (e.g., "VSMain").</param>
|
||||
/// <param name="shaderProfile">The shader model to target (e.g., "vs_5_0", "ps_5_0").</param>
|
||||
/// <returns>A byte array containing the compiled shader bytecode.</returns>
|
||||
/// <exception cref="Exception">Thrown if shader compilation fails.</exception>
|
||||
public static unsafe byte[] CompileShader(string sourceCode, string entryPoint, string shaderProfile)
|
||||
{
|
||||
ComPtr<ID3DBlob> bytecodeBlob = default;
|
||||
ComPtr<ID3DBlob> errorBlob = default;
|
||||
|
||||
// Convert strings to null-terminated ASCII for the native function
|
||||
var sourceCodeBytes = Encoding.UTF8.GetBytes(sourceCode);
|
||||
var entryPointBytes = Encoding.UTF8.GetBytes(entryPoint);
|
||||
var shaderProfileBytes = Encoding.UTF8.GetBytes(shaderProfile);
|
||||
|
||||
// Call the D3DCompile function
|
||||
var hr = D3DCompile(
|
||||
sourceCodeBytes.AsSpan(),
|
||||
entryPointBytes.AsSpan(),
|
||||
shaderProfileBytes.AsSpan(),
|
||||
CompileFlags.EnableStrictness | CompileFlags.Debug,
|
||||
bytecodeBlob.GetAddressOf(),
|
||||
errorBlob.GetAddressOf()
|
||||
);
|
||||
|
||||
if (hr.Failure)
|
||||
{
|
||||
// If compilation fails, get the error message from the error blob
|
||||
var errorMessage = "Shader compilation failed.";
|
||||
if (errorBlob.Get() is not null)
|
||||
{
|
||||
errorMessage += "\n" + Encoding.ASCII.GetString(
|
||||
(byte*)errorBlob.Get()->GetBufferPointer(),
|
||||
(int)errorBlob.Get()->GetBufferSize()
|
||||
);
|
||||
}
|
||||
errorBlob.Dispose();
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
// Copy the compiled bytecode from the blob into a managed byte array
|
||||
var bytecode = new byte[bytecodeBlob.Get()->GetBufferSize()];
|
||||
Marshal.Copy((IntPtr)bytecodeBlob.Get()->GetBufferPointer(), bytecode, 0, bytecode.Length);
|
||||
|
||||
// Clean up the COM blobs
|
||||
bytecodeBlob.Dispose();
|
||||
errorBlob.Dispose();
|
||||
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
private void LoadShader(Span<byte> byteCode)
|
||||
{
|
||||
using ComPtr<ID3D12ShaderReflection> reflector = default;
|
||||
fixed (void* codePtr = byteCode)
|
||||
{
|
||||
D3DReflect(codePtr, (nuint)byteCode.Length, __uuidof<ID3D12ShaderReflection>(), reflector.GetVoidAddressOf());
|
||||
}
|
||||
|
||||
ShaderDescription shaderDesc;
|
||||
reflector.Get()->GetDesc(&shaderDesc);
|
||||
|
||||
var rootParameters = new List<RootParameter>();
|
||||
var staticSamplers = new List<StaticSamplerDescription>();
|
||||
|
||||
for (uint i = 0; i < shaderDesc.BoundResources; i++)
|
||||
{
|
||||
ShaderInputBindDescription bindDesc;
|
||||
reflector.Get()->GetResourceBindingDesc(i, &bindDesc);
|
||||
|
||||
switch (bindDesc.Type)
|
||||
{
|
||||
case ShaderInputType.ConstantBuffer:
|
||||
var cbufferParam = new RootParameter();
|
||||
cbufferParam.ParameterType = RootParameterType.Cbv;
|
||||
cbufferParam.ShaderVisibility = ShaderVisibility.All;
|
||||
cbufferParam.Descriptor.RegisterSpace = bindDesc.Space;
|
||||
cbufferParam.Descriptor.ShaderRegister = bindDesc.BindPoint;
|
||||
|
||||
rootParameters.Add(cbufferParam);
|
||||
|
||||
var cbuffer = reflector.Get()->GetConstantBufferByName(bindDesc.Name);
|
||||
ShaderBufferDescription cbufferDesc;
|
||||
cbuffer->GetDesc(&cbufferDesc);
|
||||
|
||||
for (var j = 0u; j < cbufferDesc.Variables; j++)
|
||||
{
|
||||
var variable = cbuffer->GetVariableByIndex(j);
|
||||
ShaderVariableDescription varDesc;
|
||||
variable->GetDesc(&varDesc);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderInputType.TextureBuffer:
|
||||
break;
|
||||
case ShaderInputType.Texture:
|
||||
break;
|
||||
case ShaderInputType.Sampler:
|
||||
var samplerDesc = new StaticSamplerDescription
|
||||
{
|
||||
Filter = Filter.MinMagMipLinear,
|
||||
AddressU = TextureAddressMode.Wrap,
|
||||
AddressV = TextureAddressMode.Wrap,
|
||||
AddressW = TextureAddressMode.Wrap,
|
||||
ShaderVisibility = ShaderVisibility.All,
|
||||
ShaderRegister = bindDesc.BindPoint,
|
||||
RegisterSpace = bindDesc.Space,
|
||||
};
|
||||
staticSamplers.Add(samplerDesc);
|
||||
break;
|
||||
|
||||
case ShaderInputType.UavRwTyped:
|
||||
break;
|
||||
case ShaderInputType.Structured:
|
||||
break;
|
||||
case ShaderInputType.UavRwStructured:
|
||||
break;
|
||||
case ShaderInputType.ByteAddress:
|
||||
break;
|
||||
case ShaderInputType.UavRwByteAddress:
|
||||
break;
|
||||
case ShaderInputType.UavAppendStructured:
|
||||
break;
|
||||
case ShaderInputType.UavConsumeStructured:
|
||||
break;
|
||||
case ShaderInputType.UavRwStructuredWithCounter:
|
||||
break;
|
||||
case ShaderInputType.RtAccelerationStructure:
|
||||
break;
|
||||
case ShaderInputType.UavFeedbackTexture:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateRootSignature()
|
||||
{
|
||||
var rootSignatureDesc = new RootSignatureDescription();
|
||||
|
||||
using ComPtr<ID3DBlob> signature = default;
|
||||
using ComPtr<ID3DBlob> error = default;
|
||||
|
||||
var hr = D3D12SerializeRootSignature(&rootSignatureDesc, RootSignatureVersion.V1_2, signature.GetAddressOf(), error.GetAddressOf());
|
||||
if (hr.Failure)
|
||||
{
|
||||
var errorMessage = System.Text.Encoding.ASCII.GetString((byte*)error.Get()->GetBufferPointer(), (int)error.Get()->GetBufferSize());
|
||||
throw new Exception($"Failed to serialize root signature: {errorMessage}");
|
||||
}
|
||||
|
||||
GraphicsPipeline.GetGraphicsDevice<D3D12GraphicsDevice>().NativeDevice.Ptr->CreateRootSignature(0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(), __uuidof<ID3D12RootSignature>(), _rootSignature.GetVoidAddressOf());
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using Win32.Graphics.Direct3D;
|
||||
|
||||
namespace Ghost.Graphics.Data;
|
||||
|
||||
public class ShaderProperty
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ShaderInputType Type
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll</HintPath>
|
||||
<Reference Include="Misaki.HighPerformance.Image">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Image\bin\Release\net9.0\Misaki.HighPerformance.Image.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Misaki.HighPerformance.LowLevel">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.D3D12;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Ghost.Graphics.Data;
|
||||
using Ghost.Graphics.Shading;
|
||||
using Ghost.Graphics.Utilities;
|
||||
using System.Drawing;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Win32;
|
||||
using Win32.Graphics.Direct3D;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
using Win32.Graphics.Dxgi.Common;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ghost.Graphics.RenderPasses;
|
||||
|
||||
internal unsafe class MeshRenderPass : IRenderPass
|
||||
{
|
||||
private const string _HLSL_SOURCE = @"
|
||||
|
||||
cbuffer ConstantBuffer : register(b0)
|
||||
{
|
||||
float4x4 WVP_Matrix;
|
||||
float4 _Color;
|
||||
};
|
||||
|
||||
struct VertexInput
|
||||
@@ -43,105 +37,35 @@ PixelInput VSMain(VertexInput input)
|
||||
|
||||
float4 PSMain(PixelInput input) : SV_TARGET
|
||||
{
|
||||
return float4(1.0, 1.0, 1.0, 1.0);
|
||||
return float4(_Color.xyz, 1.0);
|
||||
}
|
||||
";
|
||||
|
||||
private Mesh? _mesh;
|
||||
|
||||
private ComPtr<ID3D12RootSignature> _rootSignature;
|
||||
private ComPtr<ID3D12PipelineState> _pipelineState;
|
||||
private Shader? _shader;
|
||||
private Material? _material;
|
||||
|
||||
public void Initialize(ICommandBuffer cmb)
|
||||
{
|
||||
_mesh = MeshBuilder.CreateCube(0.25f, new(Color.AliceBlue));
|
||||
_mesh = MeshBuilder.CreateCube(0.25f);
|
||||
_mesh.UploadMeshData(cmb);
|
||||
|
||||
CreateRootSignature();
|
||||
CreatePipelineStateObject();
|
||||
}
|
||||
_shader = new(_HLSL_SOURCE);
|
||||
_material = new(_shader);
|
||||
|
||||
private void CreateRootSignature()
|
||||
{
|
||||
var rootParameters = new RootParameter[]
|
||||
{
|
||||
new ()
|
||||
{
|
||||
ParameterType = RootParameterType.Cbv,
|
||||
ShaderVisibility = ShaderVisibility.Vertex,
|
||||
Descriptor = new RootDescriptor(0, 0)
|
||||
}
|
||||
};
|
||||
|
||||
var rootSignatureDesc = new RootSignatureDescription(0u, (RootParameter*)Unsafe.AsPointer(ref rootParameters[0]))
|
||||
{
|
||||
Flags = RootSignatureFlags.AllowInputAssemblerInputLayout
|
||||
};
|
||||
|
||||
using ComPtr<ID3DBlob> signature = default;
|
||||
using ComPtr<ID3DBlob> error = default;
|
||||
|
||||
var hr = D3D12SerializeRootSignature(&rootSignatureDesc, RootSignatureVersion.V1_0, signature.GetAddressOf(), error.GetAddressOf());
|
||||
if (hr.Failure)
|
||||
{
|
||||
var errorMessage = System.Text.Encoding.ASCII.GetString((byte*)error.Get()->GetBufferPointer(), (int)error.Get()->GetBufferSize());
|
||||
throw new InvalidOperationException($"Failed to serialize root signature: {errorMessage}");
|
||||
}
|
||||
|
||||
GraphicsPipeline.GetGraphicsDevice<D3D12GraphicsDevice>().NativeDevice.Ptr->CreateRootSignature(0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(), __uuidof<ID3D12RootSignature>(), _rootSignature.GetVoidAddressOf());
|
||||
}
|
||||
|
||||
private void CreatePipelineStateObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
var vertexShaderBytecode = Shader.CompileShader(_HLSL_SOURCE, "VSMain", "vs_5_0");
|
||||
var pixelShaderBytecode = Shader.CompileShader(_HLSL_SOURCE, "PSMain", "ps_5_0");
|
||||
|
||||
fixed (byte* vsPtr = vertexShaderBytecode)
|
||||
fixed (byte* psPtr = pixelShaderBytecode)
|
||||
{
|
||||
var psoDesc = new GraphicsPipelineStateDescription
|
||||
{
|
||||
pRootSignature = _rootSignature.Get(),
|
||||
VS = new ShaderBytecode(vsPtr, (nuint)vertexShaderBytecode.Length),
|
||||
PS = new ShaderBytecode(psPtr, (nuint)pixelShaderBytecode.Length),
|
||||
InputLayout = D3D12PipelineResource.InputLayoutDescription,
|
||||
RasterizerState = RasterizerDescription.CullNone,
|
||||
BlendState = BlendDescription.Opaque,
|
||||
DepthStencilState = DepthStencilDescription.Default,
|
||||
SampleMask = uint.MaxValue,
|
||||
PrimitiveTopologyType = PrimitiveTopologyType.Triangle,
|
||||
NumRenderTargets = 1,
|
||||
SampleDesc = new SampleDescription(1, 0),
|
||||
DSVFormat = Format.Unknown,
|
||||
};
|
||||
|
||||
psoDesc.RTVFormats[0] = D3D12PipelineResource.SWAP_CHAIN_BACK_BUFFER_FORMAT;
|
||||
|
||||
// Create the PSO
|
||||
GraphicsPipeline.GetGraphicsDevice<D3D12GraphicsDevice>().NativeDevice.Ptr->CreateGraphicsPipelineState(&psoDesc, __uuidof<ID3D12PipelineState>(), _pipelineState.GetVoidAddressOf());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
var color = new Vector4(Color.Brown.R / 255f, Color.Brown.G / 255f, Color.Brown.B / 255f, 1.0f);
|
||||
_material.SetVector("_Color", ref color);
|
||||
}
|
||||
|
||||
public void Execute(ICommandBuffer cmb)
|
||||
{
|
||||
var dx12Cmb = (D3D12CommandBuffer)cmb;
|
||||
dx12Cmb.CommandList.Ptr->SetGraphicsRootSignature(_rootSignature.Get());
|
||||
dx12Cmb.CommandList.Ptr->SetPipelineState(_pipelineState.Get());
|
||||
|
||||
cmb.DrawMesh(_mesh!);
|
||||
cmb.DrawMesh(_mesh!, _material!);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mesh?.Dispose();
|
||||
_rootSignature.Dispose();
|
||||
_pipelineState.Dispose();
|
||||
_shader?.Dispose();
|
||||
_material?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
43
Ghost.Graphics/Shading/CBufferCache.cs
Normal file
43
Ghost.Graphics/Shading/CBufferCache.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Graphics.Shading;
|
||||
|
||||
internal struct CBufferCache : IDisposable
|
||||
{
|
||||
public UnsafeArray<byte> CpuData
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public IResource GpuResource
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
private readonly uint _alignedSize;
|
||||
|
||||
public unsafe CBufferCache(uint bufferSize)
|
||||
{
|
||||
CpuData = new((int)bufferSize, Allocator.Persistent);
|
||||
|
||||
_alignedSize = (bufferSize + 255u) & ~255u;
|
||||
GpuResource = GraphicsPipeline.ResourceAllocator.CreateUploadBuffer(_alignedSize);
|
||||
GpuResource.Name = "Material_CBufferCache";
|
||||
|
||||
UploadToGpu();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void UploadToGpu()
|
||||
{
|
||||
GpuResource.SetData(CpuData.AsSpan());
|
||||
}
|
||||
|
||||
public readonly void Dispose()
|
||||
{
|
||||
GpuResource.Dispose();
|
||||
}
|
||||
}
|
||||
291
Ghost.Graphics/Shading/Shader.cs
Normal file
291
Ghost.Graphics/Shading/Shader.cs
Normal file
@@ -0,0 +1,291 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.D3D12;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Win32;
|
||||
using Win32.Graphics.Direct3D;
|
||||
using Win32.Graphics.Direct3D.Fxc;
|
||||
using Win32.Graphics.Direct3D12;
|
||||
using Win32.Graphics.Dxgi.Common;
|
||||
|
||||
namespace Ghost.Graphics.Shading;
|
||||
|
||||
internal readonly struct PropertyInfo
|
||||
{
|
||||
public required string Name
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public required string CBufferName
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe class Shader : IDisposable
|
||||
{
|
||||
private ComPtr<ID3D12PipelineState> _pipelineState;
|
||||
private ComPtr<ID3D12RootSignature> _rootSignature;
|
||||
|
||||
private readonly byte[] _vertexShaderBytecode;
|
||||
private readonly byte[] _pixelShaderBytecode;
|
||||
|
||||
private readonly Dictionary<string, CBufferInfo> _constantBuffers = new();
|
||||
private readonly Dictionary<string, PropertyInfo> _properties = new();
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
internal ConstPtr<ID3D12PipelineState> PipelineState => new(_pipelineState.Get());
|
||||
internal ConstPtr<ID3D12RootSignature> RootSignature => new(_rootSignature.Get());
|
||||
|
||||
internal IReadOnlyDictionary<string, CBufferInfo> ConstantBuffers => _constantBuffers;
|
||||
internal IReadOnlyDictionary<string, PropertyInfo> Properties => _properties;
|
||||
|
||||
//public Shader(string shaderPath)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
public Shader(string shaderCode)
|
||||
{
|
||||
_vertexShaderBytecode = CompileShader(Encoding.UTF8.GetBytes(shaderCode), "VSMain", "vs_5_0");
|
||||
_pixelShaderBytecode = CompileShader(Encoding.UTF8.GetBytes(shaderCode), "PSMain", "ps_5_0");
|
||||
|
||||
PerformReflection(_vertexShaderBytecode);
|
||||
PerformReflection(_pixelShaderBytecode);
|
||||
|
||||
CreateRootSignature();
|
||||
CreatePipelineStateObject();
|
||||
}
|
||||
|
||||
~Shader()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles HLSL source code from a string into shader bytecode.
|
||||
/// </summary>
|
||||
/// <param name="sourceCode">The string containing the HLSL code.</param>
|
||||
/// <param name="entryPoint">The name of the shader entry point function (e.g., "VSMain").</param>
|
||||
/// <param name="shaderProfile">The shader model to target (e.g., "vs_5_0", "ps_5_0").</param>
|
||||
/// <returns>A byte array containing the compiled shader bytecode.</returns>
|
||||
/// <exception cref="Exception">Thrown if shader compilation fails.</exception>
|
||||
public static unsafe byte[] CompileShader(byte[] sourceCodeBytes, string entryPoint, string shaderProfile)
|
||||
{
|
||||
using ComPtr<ID3DBlob> bytecodeBlob = default;
|
||||
using ComPtr<ID3DBlob> errorBlob = default;
|
||||
|
||||
var entryPointBytes = Encoding.UTF8.GetBytes(entryPoint);
|
||||
var shaderProfileBytes = Encoding.UTF8.GetBytes(shaderProfile);
|
||||
|
||||
// Call the D3DCompile function
|
||||
var hr = D3DCompile(
|
||||
sourceCodeBytes.AsSpan(),
|
||||
entryPointBytes.AsSpan(),
|
||||
shaderProfileBytes.AsSpan(),
|
||||
CompileFlags.EnableStrictness | CompileFlags.Debug,
|
||||
bytecodeBlob.GetAddressOf(),
|
||||
errorBlob.GetAddressOf()
|
||||
);
|
||||
|
||||
if (hr.Failure)
|
||||
{
|
||||
var errorMessage = "Shader compilation failed.";
|
||||
if (errorBlob.Get() is not null)
|
||||
{
|
||||
errorMessage += "\n" + Encoding.ASCII.GetString(
|
||||
(byte*)errorBlob.Get()->GetBufferPointer(),
|
||||
(int)errorBlob.Get()->GetBufferSize()
|
||||
);
|
||||
}
|
||||
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
var bytecode = new byte[bytecodeBlob.Get()->GetBufferSize()];
|
||||
Unsafe.CopyBlock(bytecode.AsSpan().GetPointer(), bytecodeBlob.Get()->GetBufferPointer(), (uint)bytecode.Length);
|
||||
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
private void CreateRootSignature()
|
||||
{
|
||||
var rootParameters = new RootParameter1[_constantBuffers.Values.Count];
|
||||
|
||||
var i = 0;
|
||||
foreach (var cbufferInfo in _constantBuffers.Values)
|
||||
{
|
||||
var rootParameter = new RootParameter1
|
||||
{
|
||||
ParameterType = RootParameterType.Cbv,
|
||||
ShaderVisibility = ShaderVisibility.All,
|
||||
Descriptor = new RootDescriptor1(cbufferInfo.RegisterSlot, 0),
|
||||
};
|
||||
|
||||
rootParameters[i++] = rootParameter;
|
||||
}
|
||||
|
||||
var rootSignatureDesc = new RootSignatureDescription((uint)rootParameters.Length, (RootParameter*)Unsafe.AsPointer(ref rootParameters[0]))
|
||||
{
|
||||
Flags = RootSignatureFlags.AllowInputAssemblerInputLayout
|
||||
};
|
||||
|
||||
using ComPtr<ID3DBlob> signature = default;
|
||||
using ComPtr<ID3DBlob> error = default;
|
||||
|
||||
var hr = D3D12SerializeRootSignature(&rootSignatureDesc, RootSignatureVersion.V1_0, signature.GetAddressOf(), error.GetAddressOf());
|
||||
if (hr.Failure)
|
||||
{
|
||||
var errorMessage = System.Text.Encoding.ASCII.GetString((byte*)error.Get()->GetBufferPointer(), (int)error.Get()->GetBufferSize());
|
||||
throw new InvalidOperationException($"Failed to serialize root signature: {errorMessage}");
|
||||
}
|
||||
|
||||
GraphicsPipeline.GetGraphicsDevice<D3D12GraphicsDevice>().NativeDevice.Ptr->CreateRootSignature(0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(), __uuidof<ID3D12RootSignature>(), _rootSignature.GetVoidAddressOf());
|
||||
}
|
||||
|
||||
private void CreatePipelineStateObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
fixed (byte* vsPtr = _vertexShaderBytecode)
|
||||
fixed (byte* psPtr = _pixelShaderBytecode)
|
||||
{
|
||||
var psoDesc = new GraphicsPipelineStateDescription
|
||||
{
|
||||
pRootSignature = _rootSignature.Get(),
|
||||
VS = new ShaderBytecode(vsPtr, (nuint)_vertexShaderBytecode.Length),
|
||||
PS = new ShaderBytecode(psPtr, (nuint)_pixelShaderBytecode.Length),
|
||||
InputLayout = D3D12PipelineResource.InputLayoutDescription,
|
||||
RasterizerState = RasterizerDescription.CullNone,
|
||||
BlendState = BlendDescription.Opaque,
|
||||
DepthStencilState = DepthStencilDescription.Default,
|
||||
SampleMask = uint.MaxValue,
|
||||
PrimitiveTopologyType = PrimitiveTopologyType.Triangle,
|
||||
NumRenderTargets = 1,
|
||||
SampleDesc = new SampleDescription(1, 0),
|
||||
DSVFormat = Format.Unknown,
|
||||
};
|
||||
|
||||
psoDesc.RTVFormats[0] = D3D12PipelineResource.SWAP_CHAIN_BACK_BUFFER_FORMAT;
|
||||
|
||||
// Create the PSO
|
||||
GraphicsPipeline.GetGraphicsDevice<D3D12GraphicsDevice>().NativeDevice.Ptr->CreateGraphicsPipelineState(&psoDesc, __uuidof<ID3D12PipelineState>(), _pipelineState.GetVoidAddressOf());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void PerformReflection(Span<byte> byteCode)
|
||||
{
|
||||
using ComPtr<ID3D12ShaderReflection> reflection = default;
|
||||
fixed (void* codePtr = byteCode)
|
||||
{
|
||||
D3DReflect(codePtr, (nuint)byteCode.Length, __uuidof<ID3D12ShaderReflection>(), reflection.GetVoidAddressOf());
|
||||
}
|
||||
|
||||
ShaderDescription shaderDesc;
|
||||
reflection.Get()->GetDesc(&shaderDesc);
|
||||
|
||||
for (uint i = 0; i < shaderDesc.BoundResources; i++)
|
||||
{
|
||||
ShaderInputBindDescription bindDesc;
|
||||
reflection.Get()->GetResourceBindingDesc(i, &bindDesc);
|
||||
|
||||
if (bindDesc.Type == ShaderInputType.ConstantBuffer)
|
||||
{
|
||||
var cbufferName = Marshal.PtrToStringAnsi((IntPtr)bindDesc.Name);
|
||||
if (cbufferName == null || _constantBuffers.ContainsKey(cbufferName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cbuffer = reflection.Get()->GetConstantBufferByName(bindDesc.Name);
|
||||
ShaderBufferDescription cbufferDesc;
|
||||
cbuffer->GetDesc(&cbufferDesc);
|
||||
|
||||
_constantBuffers.Add(cbufferName, new CBufferInfo
|
||||
{
|
||||
Name = cbufferName,
|
||||
Size = cbufferDesc.Size,
|
||||
RegisterSlot = bindDesc.BindPoint
|
||||
});
|
||||
|
||||
for (uint j = 0; j < cbufferDesc.Variables; j++)
|
||||
{
|
||||
var variable = cbuffer->GetVariableByIndex(j);
|
||||
ShaderVariableDescription varDesc;
|
||||
variable->GetDesc(&varDesc);
|
||||
|
||||
var variableName = Marshal.PtrToStringAnsi((IntPtr)varDesc.Name);
|
||||
if (variableName == null || _properties.ContainsKey(variableName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_properties.Add(variableName, new PropertyInfo
|
||||
{
|
||||
Name = variableName,
|
||||
CBufferName = cbufferName,
|
||||
ByteOffset = varDesc.StartOffset,
|
||||
Size = varDesc.Size
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
reflection.Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_pipelineState.Dispose();
|
||||
_rootSignature.Dispose();
|
||||
|
||||
_constantBuffers.Clear();
|
||||
_properties.Clear();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
48
Ghost.Graphics/Shading/ShaderProperty.cs
Normal file
48
Ghost.Graphics/Shading/ShaderProperty.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Helpers;
|
||||
|
||||
namespace Ghost.Graphics.Shading;
|
||||
|
||||
public enum ShaderPropertyType
|
||||
{
|
||||
Float,
|
||||
Float2,
|
||||
Float3,
|
||||
Float4,
|
||||
Color,
|
||||
Matrix,
|
||||
Texture2D,
|
||||
Texture3D
|
||||
}
|
||||
|
||||
public struct ShaderProperty : IDisposable
|
||||
{
|
||||
private UnsafeArray<byte> _value;
|
||||
private FixedString128 _name;
|
||||
private readonly uint _valueOffset;
|
||||
|
||||
internal readonly uint Offset => _valueOffset;
|
||||
|
||||
public readonly string Name => _name.Value;
|
||||
public readonly ReadOnlySpan<byte> Value => _value.AsSpan();
|
||||
|
||||
public ShaderPropertyType PropertyType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ShaderProperty(Span<byte> value, uint offset, string name, ShaderPropertyType type)
|
||||
{
|
||||
_value = new(value.Length, Allocator.Persistent);
|
||||
_valueOffset = offset;
|
||||
_name = new(name);
|
||||
PropertyType = type;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_value.Dispose();
|
||||
_name.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll</HintPath>
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application
|
||||
x:Class="Ghost.UnitTest.UnitTestApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
|
||||
@@ -2,7 +2,6 @@ using Ghost.Graphics;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Misaki.HighPerformance.Unsafe.Buffer;
|
||||
using WinRT;
|
||||
|
||||
namespace Ghost.UnitTest;
|
||||
@@ -32,7 +31,6 @@ public sealed partial class UnitTestAppWindow : Window
|
||||
|
||||
private void UnitTestAppWindow_Activated(object sender, WindowActivatedEventArgs args)
|
||||
{
|
||||
AllocationManager.Initialize();
|
||||
GraphicsPipeline.Initialize(Graphics.Data.GraphicsAPI.D3D12);
|
||||
GraphicsPipeline.Start();
|
||||
|
||||
@@ -49,7 +47,6 @@ public sealed partial class UnitTestAppWindow : Window
|
||||
{
|
||||
GraphicsPipeline.SignalCPUReady();
|
||||
GraphicsPipeline.Shutdown();
|
||||
AllocationManager.Dispose();
|
||||
CompositionTarget.Rendering -= OnRendering;
|
||||
_swapChainPanelNative.Dispose();
|
||||
_renderView?.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user