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:
@@ -307,7 +307,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var shaderPipeline = _pipelineLibrary.LoadGraphicsPSO(pipelineKey).GetValueOrThrow();
|
||||
var shaderPipeline = _pipelineLibrary.GetGraphicsPSO(pipelineKey).GetValueOrThrow();
|
||||
_commandList.Get()->SetPipelineState(shaderPipeline.value);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
#endif
|
||||
|
||||
private readonly D3D12RenderDevice _device;
|
||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||
private readonly D3D12ResourceAllocator _resourceAllocator;
|
||||
private readonly D3D12CommandBuffer _copyCommandBuffer;
|
||||
|
||||
@@ -37,9 +37,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
_descriptorAllocator = new(_device);
|
||||
|
||||
_resourceDatabase = new(_descriptorAllocator);
|
||||
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase);
|
||||
|
||||
_pipelineLibrary = new(_device, _resourceDatabase);
|
||||
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
||||
|
||||
_copyCommandBuffer = new(
|
||||
_device,
|
||||
_pipelineLibrary,
|
||||
@@ -112,6 +112,8 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
{
|
||||
renderer.ExecutePendingResize();
|
||||
}
|
||||
|
||||
_copyCommandBuffer.Begin();
|
||||
}
|
||||
|
||||
public void RenderFrame()
|
||||
@@ -127,6 +129,8 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
public void EndFrame()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
_copyCommandBuffer.End();
|
||||
_resourceAllocator.ReleaseTempResources();
|
||||
}
|
||||
|
||||
@@ -138,9 +142,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
}
|
||||
|
||||
_copyCommandBuffer.Dispose();
|
||||
_pipelineLibrary.Dispose();
|
||||
|
||||
_resourceAllocator.Dispose();
|
||||
_pipelineLibrary.Dispose();
|
||||
_resourceDatabase.Dispose();
|
||||
|
||||
_descriptorAllocator.Dispose();
|
||||
|
||||
@@ -7,7 +7,6 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||
using Misaki.HighPerformance.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
@@ -22,6 +21,7 @@ internal struct D3D12GraphicsCompiledResult : IDisposable
|
||||
public CompileResult tsResult;
|
||||
public CompileResult msResult;
|
||||
public CompileResult psResult;
|
||||
public CBufferInfo cbufferInfo;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -33,14 +33,12 @@ internal struct D3D12GraphicsCompiledResult : IDisposable
|
||||
|
||||
internal struct D3D12PipelineState : IDisposable
|
||||
{
|
||||
// NOTE: This is just a temporary cache for compiled shader code. We will implement a proper disk cache later.
|
||||
public D3D12GraphicsCompiledResult compileResult;
|
||||
public D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
||||
public ComPtr<ID3D12PipelineState> pso;
|
||||
public ShaderPassKey shaderPass;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
compileResult.Dispose();
|
||||
pso.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -62,6 +60,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
private ComPtr<ID3D12RootSignature> _defaultRootSignature;
|
||||
|
||||
private readonly Dictionary<GraphicsPipelineKey, D3D12PipelineState> _pipelineCache;
|
||||
// NOTE: This is just a temporary cache for compiled shader code. We will implement a proper disk cache later.
|
||||
private readonly Dictionary<ShaderPassKey, D3D12GraphicsCompiledResult> _compiledResults;
|
||||
|
||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||
|
||||
@@ -71,6 +71,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
_resourceDatabase = resourceDatabase;
|
||||
|
||||
_pipelineCache = new();
|
||||
_compiledResults = new();
|
||||
|
||||
CreateDefaultRootSignature();
|
||||
}
|
||||
@@ -214,7 +215,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
fs.Write(buffer.AsSpan());
|
||||
}
|
||||
|
||||
private static void ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||
private static CBufferInfo ValidateReflectionData(FullPassDescriptor descriptor, ShaderReflectionData reflectionData)
|
||||
{
|
||||
if (reflectionData.ConstantBuffers.Count != rootParamCount)
|
||||
{
|
||||
@@ -226,27 +227,27 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
throw new NotSupportedException("Shader reflection data contains unsupported resource types. Only constant buffers are supported in the current root signature.");
|
||||
}
|
||||
|
||||
return reflectionData.ConstantBuffers[RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT];
|
||||
|
||||
// TODO: Validate Cbuffer sizes and bindings.
|
||||
}
|
||||
|
||||
private static Result<D3D12GraphicsCompiledResult> CompileAndValidateFullPass(FullPassDescriptor descriptor)
|
||||
private static D3D12GraphicsCompiledResult CompileAndValidateFullPass(FullPassDescriptor descriptor)
|
||||
{
|
||||
static CompileResult CompileAndValidate(ref CompilerConfig config)
|
||||
static CompileResult CompileAndValidate(ref CompilerConfig config, FullPassDescriptor descriptor)
|
||||
{
|
||||
IDxcBlob* reflectionBlob = default;
|
||||
CBufferInfo cbufferInfo = default;
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: This does not include generated code. This will cause a root signature mismatch.
|
||||
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow();
|
||||
|
||||
#if false
|
||||
if (reflectionBlob != null)
|
||||
{
|
||||
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
|
||||
ValidateReflectionData(reflection);
|
||||
cbufferInfo = ValidateReflectionData(descriptor, reflection);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -266,7 +267,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
var config = new CompilerConfig
|
||||
{
|
||||
defines = descriptor.defines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
include = descriptor.generatedCodePath,
|
||||
shaderPath = tsEntry.shader,
|
||||
entryPoint = tsEntry.entry,
|
||||
stage = ShaderStage.TaskShader,
|
||||
@@ -275,7 +276,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
options = CompilerOption.KeepReflections,
|
||||
};
|
||||
|
||||
tsResult = CompileAndValidate(ref config);
|
||||
tsResult = CompileAndValidate(ref config, descriptor);
|
||||
}
|
||||
|
||||
CompileResult msResult;
|
||||
@@ -285,7 +286,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
var config = new CompilerConfig
|
||||
{
|
||||
defines = descriptor.defines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
include = descriptor.generatedCodePath,
|
||||
shaderPath = msEntry.shader,
|
||||
entryPoint = msEntry.entry,
|
||||
stage = ShaderStage.MeshShader,
|
||||
@@ -294,11 +295,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
options = CompilerOption.KeepReflections,
|
||||
};
|
||||
|
||||
msResult = CompileAndValidate(ref config);
|
||||
msResult = CompileAndValidate(ref config, descriptor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result<D3D12GraphicsCompiledResult>.Fail("Mesh shader expected.");
|
||||
throw new InvalidOperationException("Mesh shader expected.");
|
||||
}
|
||||
|
||||
CompileResult psResult;
|
||||
@@ -308,7 +309,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
var config = new CompilerConfig
|
||||
{
|
||||
defines = descriptor.defines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
include = descriptor.generatedCodePath,
|
||||
shaderPath = psEntry.shader,
|
||||
entryPoint = psEntry.entry,
|
||||
stage = ShaderStage.PixelShader,
|
||||
@@ -317,11 +318,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
options = CompilerOption.KeepReflections,
|
||||
};
|
||||
|
||||
psResult = CompileAndValidate(ref config);
|
||||
psResult = CompileAndValidate(ref config, descriptor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result<D3D12GraphicsCompiledResult>.Fail("Pixel shader expected.");
|
||||
throw new InvalidOperationException("Pixel shader expected.");
|
||||
}
|
||||
|
||||
return new D3D12GraphicsCompiledResult
|
||||
@@ -353,6 +354,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
return D3D12Utility.D3D12_DEPTH_STENCIL_DESC_CREATE(depthEnabled, writeEnabled, cmp);
|
||||
}
|
||||
|
||||
private bool TryGetCompiledCache(ShaderPassKey passKey, out D3D12GraphicsCompiledResult compiled)
|
||||
{
|
||||
return _compiledResults.TryGetValue(passKey, out compiled);
|
||||
}
|
||||
|
||||
private GraphicsPipelineKey CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly D3D12GraphicsCompiledResult compiled)
|
||||
{
|
||||
var rtvCount = (uint)Math.Min(descriptor.rtvFormats.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
|
||||
@@ -412,7 +418,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
ref var existing = ref CollectionsMarshal.GetValueRefOrAddDefault(_pipelineCache, key, out var exists);
|
||||
if (!exists)
|
||||
{
|
||||
existing.compileResult = compiled;
|
||||
existing.psoDesc = desc;
|
||||
|
||||
var meshStream = new CD3DX12_PIPELINE_MESH_STATE_STREAM(in desc);
|
||||
@@ -448,14 +453,22 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
|
||||
public GraphicsPipelineKey CompilePassPSO(IPassDescriptor descriptor, ReadOnlySpan<TextureFormat> rtvs, TextureFormat dsv)
|
||||
{
|
||||
var key = default(GraphicsPipelineKey);
|
||||
GraphicsPipelineKey key = default;
|
||||
|
||||
var passKey = new ShaderPassKey(descriptor.Identifier);
|
||||
var hasCompiledCache = TryGetCompiledCache(passKey, out var compiled);
|
||||
|
||||
switch (descriptor)
|
||||
{
|
||||
case FullPassDescriptor fullPass:
|
||||
var result = CompileAndValidateFullPass(fullPass).GetValueOrThrow();
|
||||
if (!hasCompiledCache)
|
||||
{
|
||||
compiled = CompileAndValidateFullPass(fullPass);
|
||||
}
|
||||
|
||||
var psoDes = new GraphicsPSODescriptor
|
||||
{
|
||||
passId = new(fullPass.Identifier),
|
||||
passId = new ShaderPassKey(fullPass.Identifier),
|
||||
zTest = fullPass.localPipeline.zTest,
|
||||
zWrite = fullPass.localPipeline.zWrite,
|
||||
cull = fullPass.localPipeline.cull,
|
||||
@@ -466,10 +479,17 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
dsvFormat = dsv,
|
||||
};
|
||||
|
||||
key = CompilePSO(in psoDes, in result);
|
||||
key = CompilePSO(in psoDes, in compiled);
|
||||
break;
|
||||
|
||||
// Do we need to support other pass types?
|
||||
case FallbackPassDescriptor:
|
||||
if (!hasCompiledCache)
|
||||
{
|
||||
throw new ArgumentException("FallbackPassDescriptor is not supported for PSO compilation. There may be some inheritance dependency issues.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -478,15 +498,24 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
||||
return key;
|
||||
}
|
||||
|
||||
public Result<Ptr<ID3D12PipelineState>> LoadGraphicsPSO(GraphicsPipelineKey key)
|
||||
public Result<Ptr<ID3D12PipelineState>> GetGraphicsPSO(GraphicsPipelineKey key)
|
||||
{
|
||||
ref var cacheEntry = ref CollectionsMarshal.GetValueRefOrNullRef(_pipelineCache, key);
|
||||
if (Unsafe.IsNullRef(ref cacheEntry))
|
||||
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||
{
|
||||
return Result.Fail("Pipeline state not found in cache.");
|
||||
return new Ptr<ID3D12PipelineState>(cacheEntry.pso.Get());
|
||||
}
|
||||
|
||||
return new Ptr<ID3D12PipelineState>(cacheEntry.pso.Get());
|
||||
return Result.Fail("Pipeline state not found in cache.");
|
||||
}
|
||||
|
||||
public Result<CBufferInfo> GetCBufferInfo(ShaderPassKey key)
|
||||
{
|
||||
if (_compiledResults.TryGetValue(key, out var compiled))
|
||||
{
|
||||
return compiled.cbufferInfo;
|
||||
}
|
||||
|
||||
return Result.Fail("Compiled shader not found in cache.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -210,6 +210,13 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
clearStencil = 0,
|
||||
};
|
||||
|
||||
// NOTE: Testing only.
|
||||
var ctx = new RenderingContext(_graphicsEngine, cmd, _graphicsEngine.CopyCommandBuffer, null!);
|
||||
if (_frameIndex == 0)
|
||||
{
|
||||
_pass.Initialize(ref ctx);
|
||||
}
|
||||
|
||||
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
||||
|
||||
var viewport = new ViewportDesc { width = _currentSize.x, height = _currentSize.y, minDepth = 0, maxDepth = 1 };
|
||||
@@ -219,12 +226,6 @@ internal unsafe class D3D12Renderer : IRenderer
|
||||
cmd.SetScissorRect(scissor);
|
||||
|
||||
// NOTE: Testing only.
|
||||
var ctx = new RenderingContext(_graphicsEngine, cmd, _graphicsEngine.CopyCommandBuffer, null!);
|
||||
if (_frameIndex == 0)
|
||||
{
|
||||
_pass.Initialize(ref ctx);
|
||||
}
|
||||
|
||||
_pass.Execute(ref ctx);
|
||||
|
||||
cmd.EndRenderPass();
|
||||
|
||||
@@ -597,13 +597,19 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
private readonly D3D12RenderDevice _device;
|
||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||
|
||||
private ComPtr<D3D12MA_Allocator> _allocator;
|
||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public D3D12ResourceAllocator(IFenceSynchronizer fenceSynchronizer, D3D12RenderDevice device, D3D12DescriptorAllocator descriptorAllocator, D3D12ResourceDatabase resourceDatabase)
|
||||
public D3D12ResourceAllocator(
|
||||
IFenceSynchronizer fenceSynchronizer,
|
||||
D3D12RenderDevice device,
|
||||
D3D12DescriptorAllocator descriptorAllocator,
|
||||
D3D12ResourceDatabase resourceDatabase,
|
||||
D3D12PipelineLibrary pipelineLibrary)
|
||||
{
|
||||
var desc = new D3D12MA_ALLOCATOR_DESC
|
||||
{
|
||||
@@ -616,10 +622,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
||||
_allocator.Attach(pAllocator);
|
||||
|
||||
_device = device;
|
||||
_fenceSynchronizer = fenceSynchronizer;
|
||||
_device = device;
|
||||
_descriptorAllocator = descriptorAllocator;
|
||||
_resourceDatabase = resourceDatabase;
|
||||
_pipelineLibrary = pipelineLibrary;
|
||||
|
||||
_temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||
}
|
||||
@@ -869,6 +876,18 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
public Identifier<Shader> CreateShader(ShaderDescriptor descriptor)
|
||||
{
|
||||
var shader = new Shader(descriptor);
|
||||
foreach (var pass in descriptor.passes)
|
||||
{
|
||||
if (pass is not FullPassDescriptor fullPass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var passKey = new ShaderPassKey(fullPass.uniqueIdentifier);
|
||||
var cbufferInfo = _pipelineLibrary.GetCBufferInfo(passKey).GetValueOrThrow();
|
||||
_resourceDatabase.AddShaderPass(new ShaderPassKey(fullPass.uniqueIdentifier), new ShaderPass(cbufferInfo));
|
||||
}
|
||||
|
||||
return _resourceDatabase.AddShader(shader);
|
||||
}
|
||||
|
||||
|
||||
@@ -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