Added `InternalsVisibleTo` attribute for "Ghost.Graphics" and "Ghost.Editor" in `AssemblyInfo.cs`. Added a new `EngineAssemblyAttribute` in `EngineAssemblyAttribute.cs`. Added a reference to `Misaki.HighPerformance.Unsafe` in `Ghost.Core.csproj`. Added a new `Bounds` struct to represent axis-aligned bounding boxes in `Bounds.cs`. Added new `Color32` and `Color128` structs for color representation in `Color.cs`. Changed the namespace from `Ghost.Editor.Controls` to `Ghost.Editor.Core.Controls` in multiple files. Changed the implicit conversion operator in `ConstPtr<T>` to use a more descriptive parameter name in `ConstPtr.cs`. Changed the `Mesh` class to use `Color128` instead of `Color32` for color representation. Enhanced the `TypeCache` class to load types from assemblies marked with `EngineAssemblyAttribute`. Enhanced the `ProjectService` class to improve the `GetAllProjectAsync` method by filtering out bad projects. Enhanced the `GraphicsPipeline` class to support both DX12 and D3D12 graphics APIs. Enhanced the `Shader` class to include methods for compiling HLSL shaders and managing root signatures. Enhanced the `MeshRenderPass` class to utilize the new shader compilation methods. Refactored the `AppStateMachine` class to use private fields instead of static fields for state management. Refactored the `ComponentDataView` class to use the new namespace and improve organization. Refactored project references in `Ghost.Graphics.csproj` to include new dependencies and remove outdated ones. Made various adjustments to ensure consistency and improve code quality across multiple files.
181 lines
7.1 KiB
C#
181 lines
7.1 KiB
C#
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());
|
|
}
|
|
} |