Refactor shader pipeline and improve modularity
- Added `generatedCodePath` to `FullPassDescriptor` for better shader code organization. - Removed redundant `IID_PPV_ARGS` method and unused `Misaki.HighPerformance.Unsafe` reference. - Refactored `Material` and `MaterialAccessor` to use `CBuffer` and updated buffer size handling. - Renamed command buffer variables in `RenderingContext` for consistency. - Updated `D3D12PipelineLibrary` to cache compiled shader results and added `ShaderPassKey`. - Refactored `D3D12GraphicsEngine` to integrate `_copyCommandBuffer` lifecycle. - Enhanced `D3D12ResourceAllocator` with shader pass creation using constant buffer info. - Simplified `D3D12ShaderCompiler` with `GENERATED_CODE_PATH` support and improved reflection handling. - Introduced `CBufferPropertyInfo` and `CBufferInfo` structs for better encapsulation. - Updated HLSL shaders to use `g_PerMaterialData` and dynamic includes. - Improved error handling in `SDLCompiler` with try-catch blocks and better messages. - Refactored `test.gshader` to use dynamically generated includes. - Fixed typos, improved code readability, and removed unused code.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
using static TerraFX.Interop.DirectX.DXC;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal struct CompileResult : IDisposable
|
||||
@@ -22,52 +22,6 @@ internal struct CompileResult : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct CBufferVariableInfo
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public uint StartOffset
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public uint Size
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct CBufferInfo
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public uint RegisterSlot
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public uint RegisterSpace
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public uint SizeInBytes
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public IReadOnlyList<CBufferVariableInfo> Variables
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct ResourceBindingInfo
|
||||
{
|
||||
public string Name
|
||||
@@ -145,10 +99,10 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
CompilerOptimizeLevel.O0 => "-O0",
|
||||
CompilerOptimizeLevel.O1 => "-O1",
|
||||
CompilerOptimizeLevel.O2 => "-O2",
|
||||
CompilerOptimizeLevel.O3 => "-O3",
|
||||
CompilerOptimizeLevel.O0 => DXC_ARG_OPTIMIZATION_LEVEL0,
|
||||
CompilerOptimizeLevel.O1 => DXC_ARG_OPTIMIZATION_LEVEL1,
|
||||
CompilerOptimizeLevel.O2 => DXC_ARG_OPTIMIZATION_LEVEL2,
|
||||
CompilerOptimizeLevel.O3 => DXC_ARG_OPTIMIZATION_LEVEL3,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), "Unsupported optimization level")
|
||||
};
|
||||
}
|
||||
@@ -164,18 +118,20 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
GetOptimizeLevelString(config.optimizeLevel), // Optimization level
|
||||
};
|
||||
|
||||
foreach (var include in config.includes)
|
||||
{
|
||||
argsArray.Add("-I");
|
||||
argsArray.Add(include);
|
||||
}
|
||||
|
||||
foreach (var define in config.defines)
|
||||
{
|
||||
argsArray.Add("-D");
|
||||
argsArray.Add(define);
|
||||
}
|
||||
|
||||
// HACK: Currently DXC does not support force include, we have to use GENERATED_CODE_PATH define as a workaround.
|
||||
// User must to write '#include GENERATED_CODE_PATH' in their shader code manually.
|
||||
if (File.Exists(config.include))
|
||||
{
|
||||
argsArray.Add("-D");
|
||||
argsArray.Add($"GENERATED_CODE_PATH={'"' + config.include.Replace("\\", "/") + '"'}");
|
||||
}
|
||||
|
||||
if (!config.options.HasFlag(CompilerOption.KeepDebugInfo))
|
||||
{
|
||||
argsArray.Add("-Qstrip_debug");
|
||||
@@ -188,7 +144,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
|
||||
if (config.options.HasFlag(CompilerOption.WarnAsError))
|
||||
{
|
||||
argsArray.Add("-WX");
|
||||
argsArray.Add(DXC_ARG_WARNINGS_ARE_ERRORS);
|
||||
}
|
||||
|
||||
return argsArray;
|
||||
@@ -210,8 +166,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
ThrowIfFailed(DxcCreateInstance(&dxccID, __uuidof(pCompiler), (void**)&pCompiler));
|
||||
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
|
||||
|
||||
//pIncludeHandler.Get()->LoadSource();
|
||||
pUtils->CreateDefaultIncludeHandler(&pIncludeHandler);
|
||||
ThrowIfFailed(pUtils->CreateDefaultIncludeHandler(&pIncludeHandler));
|
||||
|
||||
// Create source blob
|
||||
using ComPtr<IDxcBlobEncoding> sourceBlob = default;
|
||||
@@ -239,7 +194,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
{
|
||||
Ptr = sourceBlob.Get()->GetBufferPointer(),
|
||||
Size = sourceBlob.Get()->GetBufferSize(),
|
||||
Encoding = DXC.DXC_CP_UTF8
|
||||
Encoding = DXC_CP_UTF8
|
||||
};
|
||||
|
||||
ThrowIfFailed(pCompiler->Compile(&buffer, argPtrs, (uint)argsArray.Count, pIncludeHandler, __uuidof(pResult), (void**)&pResult));
|
||||
@@ -268,7 +223,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
using ComPtr<IDxcBlob> bytecodeBlob = default;
|
||||
ThrowIfFailed(pResult->GetResult(bytecodeBlob.GetAddressOf()));
|
||||
|
||||
// Get reflection data using DXC API
|
||||
// Get pReflection data using DXC API
|
||||
if (ppReflectionBlob != null)
|
||||
{
|
||||
ThrowIfFailed(pResult->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof<IDxcBlob>(), (void**)ppReflectionBlob, null));
|
||||
@@ -302,8 +257,8 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Since we are using fixed root signature layout, the reflection pass should only validate the layout, not generate it.
|
||||
// TODO: Ideally this should return a structured reflection data instead of populating raw lists/dictionaries.
|
||||
// TODO: Since we are using fixed root signature layout, the pReflection pass should only validate the layout, not generate it.
|
||||
// TODO: Ideally this should return a structured pReflection data instead of populating raw lists/dictionaries.
|
||||
public static Result<ShaderReflectionData> PerformDXCReflection(IDxcBlob* reflectionBlob)
|
||||
{
|
||||
if (reflectionBlob == null)
|
||||
@@ -311,34 +266,34 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
return Result<ShaderReflectionData>.Fail("Reflection blob is null.");
|
||||
}
|
||||
|
||||
ComPtr<IDxcUtils> utils = default;
|
||||
ComPtr<ID3D12ShaderReflection> reflection = default;
|
||||
IDxcUtils* pUtils = default;
|
||||
ID3D12ShaderReflection* pReflection = default;
|
||||
|
||||
try
|
||||
{
|
||||
// Create DXC pUtils to parse reflection data
|
||||
// Create DXC pUtils to parse pReflection data
|
||||
var dxcuID = CLSID.CLSID_DxcUtils;
|
||||
ThrowIfFailed(DxcCreateInstance(&dxcuID, utils.IID(), utils.PPV()));
|
||||
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
|
||||
|
||||
// Create reflection interface from blob
|
||||
// Create pReflection interface from blob
|
||||
var reflectionBuffer = new DxcBuffer
|
||||
{
|
||||
Ptr = reflectionBlob->GetBufferPointer(),
|
||||
Size = reflectionBlob->GetBufferSize(),
|
||||
Encoding = DXC.DXC_CP_ACP
|
||||
Encoding = DXC_CP_ACP
|
||||
};
|
||||
|
||||
ThrowIfFailed(utils.Get()->CreateReflection(&reflectionBuffer, reflection.IID(), reflection.PPV()));
|
||||
ThrowIfFailed(pUtils->CreateReflection(&reflectionBuffer, __uuidof(pReflection), (void**)&pReflection));
|
||||
|
||||
D3D12_SHADER_DESC shaderDesc;
|
||||
ThrowIfFailed(reflection.Get()->GetDesc(&shaderDesc));
|
||||
ThrowIfFailed(pReflection->GetDesc(&shaderDesc));
|
||||
|
||||
var reflectionData = new ShaderReflectionData();
|
||||
|
||||
for (uint i = 0; i < shaderDesc.BoundResources; i++)
|
||||
{
|
||||
D3D12_SHADER_INPUT_BIND_DESC bindDesc;
|
||||
ThrowIfFailed(reflection.Get()->GetResourceBindingDesc(i, &bindDesc));
|
||||
ThrowIfFailed(pReflection->GetResourceBindingDesc(i, &bindDesc));
|
||||
|
||||
var resourceName = Marshal.PtrToStringUTF8((IntPtr)bindDesc.Name);
|
||||
if (resourceName == null)
|
||||
@@ -350,11 +305,11 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
{
|
||||
case D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER:
|
||||
{
|
||||
var cbuffer = reflection.Get()->GetConstantBufferByName(bindDesc.Name);
|
||||
var cbuffer = pReflection->GetConstantBufferByName(bindDesc.Name);
|
||||
D3D12_SHADER_BUFFER_DESC cbufferDesc;
|
||||
ThrowIfFailed(cbuffer->GetDesc(&cbufferDesc));
|
||||
|
||||
var variables = new List<CBufferVariableInfo>((int)cbufferDesc.Variables);
|
||||
var variables = new List<CBufferPropertyInfo>((int)cbufferDesc.Variables);
|
||||
|
||||
// Now we iterate all variables for *every* cbuffer, not just b3
|
||||
for (uint j = 0; j < cbufferDesc.Variables; j++)
|
||||
@@ -369,7 +324,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
continue;
|
||||
}
|
||||
|
||||
variables.Add(new CBufferVariableInfo
|
||||
variables.Add(new CBufferPropertyInfo
|
||||
{
|
||||
Name = variableName,
|
||||
StartOffset = varDesc.StartOffset,
|
||||
@@ -383,7 +338,7 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
RegisterSlot = bindDesc.BindPoint,
|
||||
RegisterSpace = bindDesc.Space,
|
||||
SizeInBytes = cbufferDesc.Size,
|
||||
Variables = variables
|
||||
Properties = variables
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -411,8 +366,8 @@ internal static unsafe class D3D12ShaderCompiler
|
||||
}
|
||||
finally
|
||||
{
|
||||
utils.Dispose();
|
||||
reflection.Dispose();
|
||||
pUtils->Release();
|
||||
pReflection->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user