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:
@@ -77,6 +77,7 @@ public class FullPassDescriptor : IPassDescriptor
|
|||||||
public ShaderEntryPoint taskShader;
|
public ShaderEntryPoint taskShader;
|
||||||
public ShaderEntryPoint meshShader;
|
public ShaderEntryPoint meshShader;
|
||||||
public ShaderEntryPoint pixelShader;
|
public ShaderEntryPoint pixelShader;
|
||||||
|
public string? generatedCodePath;
|
||||||
public List<string>? defines;
|
public List<string>? defines;
|
||||||
public List<string>? includes;
|
public List<string>? includes;
|
||||||
public List<KeywordsGroup>? keywords;
|
public List<KeywordsGroup>? keywords;
|
||||||
@@ -101,4 +102,4 @@ public class ShaderDescriptor
|
|||||||
public string name = string.Empty;
|
public string name = string.Empty;
|
||||||
public List<PropertyDescriptor> globalProperties = new();
|
public List<PropertyDescriptor> globalProperties = new();
|
||||||
public List<IPassDescriptor> passes = new();
|
public List<IPassDescriptor> passes = new();
|
||||||
}
|
}
|
||||||
@@ -41,13 +41,6 @@ internal static unsafe partial class Win32Utility
|
|||||||
return new IID_PPV(Windows.__uuidof<T>(), comPtr.PPV());
|
return new IID_PPV(Windows.__uuidof<T>(), comPtr.PPV());
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static IID_PPV IID_PPV_ARGS<T>(T** ppv)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return new IID_PPV(Windows.__uuidof<T>(), (void**)ppv);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Assert(this HRESULT hr)
|
public static void Assert(this HRESULT hr)
|
||||||
|
|||||||
@@ -38,12 +38,6 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
|
||||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Template\ForEach.tt">
|
<None Update="Template\ForEach.tt">
|
||||||
<Generator>TextTemplatingFileGenerator</Generator>
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
|||||||
@@ -63,17 +63,17 @@ public struct Material : IResourceReleasable, IHandleType
|
|||||||
for (var i = 0; i < shader.PassCount; i++)
|
for (var i = 0; i < shader.PassCount; i++)
|
||||||
{
|
{
|
||||||
var pass = database.GetShaderPass(shader.GetPassKey(i));
|
var pass = database.GetShaderPass(shader.GetPassKey(i));
|
||||||
var cbufferInfo = pass.PassPropertyInfo;
|
var cbufferInfo = pass.CBuffer;
|
||||||
|
|
||||||
var desc = new BufferDesc
|
var desc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = cbufferInfo.Size,
|
Size = cbufferInfo.SizeInBytes,
|
||||||
Usage = BufferUsage.Constant,
|
Usage = BufferUsage.Constant,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
MemoryType = ResourceMemoryType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer = allocator.CreateBuffer(ref desc);
|
var buffer = allocator.CreateBuffer(ref desc);
|
||||||
_materialPropertiesCache[i] = new CBufferCache(buffer, cbufferInfo.Size);
|
_materialPropertiesCache[i] = new CBufferCache(buffer, cbufferInfo.SizeInBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ public ref struct MaterialAccessor
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref var cache = ref _materialData.GetPassCache(index);
|
ref var cache = ref _materialData.GetPassCache(index);
|
||||||
Unsafe.WriteUnaligned(ref cache.CpuData[propertyInfo.ByteOffset], value);
|
Unsafe.WriteUnaligned(ref cache.CpuData[propertyInfo.StartOffset], value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ namespace Ghost.Graphics.Core;
|
|||||||
public unsafe readonly ref struct RenderingContext
|
public unsafe readonly ref struct RenderingContext
|
||||||
{
|
{
|
||||||
private readonly IGraphicsEngine _engine;
|
private readonly IGraphicsEngine _engine;
|
||||||
private readonly ICommandBuffer _directCmb;
|
private readonly ICommandBuffer _directCmd;
|
||||||
private readonly ICommandBuffer _copyCmb;
|
private readonly ICommandBuffer _copyCmd;
|
||||||
private readonly ICommandBuffer _computeCmb;
|
private readonly ICommandBuffer _computeCmd;
|
||||||
|
|
||||||
public ICommandBuffer DirectCommandBuffer => _directCmb;
|
public ICommandBuffer DirectCommandBuffer => _directCmd;
|
||||||
public ICommandBuffer CopyCommandBuffer => _copyCmb;
|
public ICommandBuffer CopyCommandBuffer => _copyCmd;
|
||||||
public ICommandBuffer ComputeCommandBuffer => _computeCmb;
|
public ICommandBuffer ComputeCommandBuffer => _computeCmd;
|
||||||
|
|
||||||
public IResourceAllocator ResourceAllocator => _engine.ResourceAllocator;
|
public IResourceAllocator ResourceAllocator => _engine.ResourceAllocator;
|
||||||
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
|
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
|
||||||
@@ -29,9 +29,9 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
ICommandBuffer computeCmd)
|
ICommandBuffer computeCmd)
|
||||||
{
|
{
|
||||||
_engine = engine;
|
_engine = engine;
|
||||||
_directCmb = directCmd;
|
_directCmd = directCmd;
|
||||||
_copyCmb = copyCmd;
|
_copyCmd = copyCmd;
|
||||||
_computeCmb = computeCmd;
|
_computeCmd = computeCmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommandBuffer CrearteCommandBuffer(CommandBufferType type)
|
public ICommandBuffer CrearteCommandBuffer(CommandBufferType type)
|
||||||
@@ -88,29 +88,25 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
||||||
ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
||||||
ResourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), ResourceState.CopyDest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_copyCmb.UploadBuffer<Vertex>(meshData.vertexBuffer, meshData.vertices.AsSpan());
|
_directCmd.UploadBuffer(meshData.vertexBuffer, meshData.vertices.AsSpan());
|
||||||
_copyCmb.UploadBuffer<uint>(meshData.indexBuffer, meshData.indices.AsSpan());
|
_directCmd.UploadBuffer(meshData.indexBuffer, meshData.indices.AsSpan());
|
||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
_directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
||||||
ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
ResourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState);
|
_directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
||||||
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markMeshStatic)
|
if (markMeshStatic)
|
||||||
@@ -141,20 +137,18 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
{
|
{
|
||||||
_copyCmb.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
||||||
ResourceDatabase.SetResourceState(texture.AsResource(), ResourceState.CopyDest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_copyCmb.UploadTexture(texture, subresourceData);
|
_directCmd.UploadTexture(texture, subresourceData);
|
||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
{
|
{
|
||||||
_copyCmb.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
|
_directCmd.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
|
||||||
ResourceDatabase.SetResourceState(texture.AsResource(), sateBefore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline.
|
// TODO: Ideally we should queue the draw call to our rendering system, and render it in a full rendering pipeline.
|
||||||
// This is just a place holder for now for testing purpose.
|
// This is just a place holder for now for testing purpose.
|
||||||
public void DispatchMesh(Handle<Mesh> mesh, Handle<Material> material, string passName, uint numThreadsX)
|
public void DispatchMesh(Handle<Mesh> mesh, Handle<Material> material, string passName, uint numThreadsX)
|
||||||
{
|
{
|
||||||
@@ -172,20 +166,20 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm;
|
hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm;
|
||||||
var pipelineKey = hash.GetKey();
|
var pipelineKey = hash.GetKey();
|
||||||
_directCmb.SetPipelineState(pipelineKey);
|
_directCmd.SetPipelineState(pipelineKey);
|
||||||
|
|
||||||
// NOTE: We use fixed root signature layout for bindless rendering.
|
// NOTE: We use fixed root signature layout for bindless rendering.
|
||||||
ref var cache = ref materialRef.GetPassCache(passIndex);
|
ref var cache = ref materialRef.GetPassCache(passIndex);
|
||||||
_directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
|
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
|
||||||
|
|
||||||
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
|
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
|
||||||
// TODO: Matbe handle the transitional bindless model?
|
// TODO: Maybe handle the traditional bindless model?
|
||||||
#if false
|
#if false
|
||||||
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
|
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
|
||||||
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX;
|
var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX;
|
||||||
_directCmb.DispatchMesh(threadGroupCountX, 1, 1);
|
_directCmd.DispatchMesh(threadGroupCountX, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,66 +7,23 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public readonly struct TextureInfo
|
public class ShaderPass : IResourceReleasable
|
||||||
{
|
|
||||||
public uint RegisterSlot
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint RootParameterIndex
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct PropertyInfo
|
|
||||||
{
|
|
||||||
public uint CBufferIndex
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint ByteOffset
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Size
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct CBufferInfo
|
|
||||||
{
|
|
||||||
public uint Size
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint RegisterSlot
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe class ShaderPass : IResourceReleasable
|
|
||||||
{
|
{
|
||||||
|
private CBufferInfo _cbufferInfo;
|
||||||
// NOTE: This is for per pass cbuffer only. Global, per view, and per mesh cbuffers are fixed.
|
// NOTE: This is for per pass cbuffer only. Global, per view, and per mesh cbuffers are fixed.
|
||||||
private readonly Dictionary<string, int> _propertyLookup;
|
private readonly Dictionary<string, int> _propertyLookup;
|
||||||
private readonly UnsafeList<PropertyInfo> _properties;
|
|
||||||
|
|
||||||
internal CBufferInfo PassPropertyInfo
|
public CBufferInfo CBuffer => _cbufferInfo;
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderPass(CBufferInfo info, UnsafeList<PropertyInfo> properties, Dictionary<string, int> propertyNameToIdMap)
|
public ShaderPass(CBufferInfo info)
|
||||||
{
|
{
|
||||||
PassPropertyInfo = info;
|
_cbufferInfo = info;
|
||||||
_properties = properties;
|
|
||||||
_propertyLookup = propertyNameToIdMap;
|
_propertyLookup = new Dictionary<string, int>(info.Properties.Count);
|
||||||
|
for (var i = 0; i < info.Properties.Count; i++)
|
||||||
|
{
|
||||||
|
_propertyLookup[info.Properties[i].Name] = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetPropertyId(string propertyName)
|
public int GetPropertyId(string propertyName)
|
||||||
@@ -74,19 +31,18 @@ public unsafe class ShaderPass : IResourceReleasable
|
|||||||
return _propertyLookup.TryGetValue(propertyName, out var id) ? id : -1;
|
return _propertyLookup.TryGetValue(propertyName, out var id) ? id : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyInfo GetPropertyInfo(int id)
|
public CBufferPropertyInfo GetPropertyInfo(int id)
|
||||||
{
|
{
|
||||||
return _properties[id];
|
return _cbufferInfo.Properties[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyInfo GetPropertyInfo(string propertyName)
|
public CBufferPropertyInfo GetPropertyInfo(string propertyName)
|
||||||
{
|
{
|
||||||
return _properties[GetPropertyId(propertyName)];
|
return _cbufferInfo.Properties[GetPropertyId(propertyName)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
||||||
{
|
{
|
||||||
_properties.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var shaderPipeline = _pipelineLibrary.LoadGraphicsPSO(pipelineKey).GetValueOrThrow();
|
var shaderPipeline = _pipelineLibrary.GetGraphicsPSO(pipelineKey).GetValueOrThrow();
|
||||||
_commandList.Get()->SetPipelineState(shaderPipeline.value);
|
_commandList.Get()->SetPipelineState(shaderPipeline.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||||
|
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||||
private readonly D3D12ResourceAllocator _resourceAllocator;
|
private readonly D3D12ResourceAllocator _resourceAllocator;
|
||||||
private readonly D3D12CommandBuffer _copyCommandBuffer;
|
private readonly D3D12CommandBuffer _copyCommandBuffer;
|
||||||
|
|
||||||
@@ -37,9 +37,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
_descriptorAllocator = new(_device);
|
_descriptorAllocator = new(_device);
|
||||||
|
|
||||||
_resourceDatabase = new(_descriptorAllocator);
|
_resourceDatabase = new(_descriptorAllocator);
|
||||||
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase);
|
|
||||||
|
|
||||||
_pipelineLibrary = new(_device, _resourceDatabase);
|
_pipelineLibrary = new(_device, _resourceDatabase);
|
||||||
|
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
||||||
|
|
||||||
_copyCommandBuffer = new(
|
_copyCommandBuffer = new(
|
||||||
_device,
|
_device,
|
||||||
_pipelineLibrary,
|
_pipelineLibrary,
|
||||||
@@ -112,6 +112,8 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
{
|
{
|
||||||
renderer.ExecutePendingResize();
|
renderer.ExecutePendingResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_copyCommandBuffer.Begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderFrame()
|
public void RenderFrame()
|
||||||
@@ -127,6 +129,8 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
public void EndFrame()
|
public void EndFrame()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
_copyCommandBuffer.End();
|
||||||
_resourceAllocator.ReleaseTempResources();
|
_resourceAllocator.ReleaseTempResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,9 +142,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
_copyCommandBuffer.Dispose();
|
_copyCommandBuffer.Dispose();
|
||||||
_pipelineLibrary.Dispose();
|
|
||||||
|
|
||||||
_resourceAllocator.Dispose();
|
_resourceAllocator.Dispose();
|
||||||
|
_pipelineLibrary.Dispose();
|
||||||
_resourceDatabase.Dispose();
|
_resourceDatabase.Dispose();
|
||||||
|
|
||||||
_descriptorAllocator.Dispose();
|
_descriptorAllocator.Dispose();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using Misaki.HighPerformance.Utilities;
|
using Misaki.HighPerformance.Utilities;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -22,6 +21,7 @@ internal struct D3D12GraphicsCompiledResult : IDisposable
|
|||||||
public CompileResult tsResult;
|
public CompileResult tsResult;
|
||||||
public CompileResult msResult;
|
public CompileResult msResult;
|
||||||
public CompileResult psResult;
|
public CompileResult psResult;
|
||||||
|
public CBufferInfo cbufferInfo;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -33,14 +33,12 @@ internal struct D3D12GraphicsCompiledResult : IDisposable
|
|||||||
|
|
||||||
internal struct D3D12PipelineState : 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 D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
||||||
public ComPtr<ID3D12PipelineState> pso;
|
public ComPtr<ID3D12PipelineState> pso;
|
||||||
|
public ShaderPassKey shaderPass;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
compileResult.Dispose();
|
|
||||||
pso.Dispose();
|
pso.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,6 +60,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
private ComPtr<ID3D12RootSignature> _defaultRootSignature;
|
private ComPtr<ID3D12RootSignature> _defaultRootSignature;
|
||||||
|
|
||||||
private readonly Dictionary<GraphicsPipelineKey, D3D12PipelineState> _pipelineCache;
|
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();
|
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||||
|
|
||||||
@@ -71,6 +71,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
_pipelineCache = new();
|
_pipelineCache = new();
|
||||||
|
_compiledResults = new();
|
||||||
|
|
||||||
CreateDefaultRootSignature();
|
CreateDefaultRootSignature();
|
||||||
}
|
}
|
||||||
@@ -214,7 +215,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
fs.Write(buffer.AsSpan());
|
fs.Write(buffer.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateReflectionData(ShaderReflectionData reflectionData)
|
private static CBufferInfo ValidateReflectionData(FullPassDescriptor descriptor, ShaderReflectionData reflectionData)
|
||||||
{
|
{
|
||||||
if (reflectionData.ConstantBuffers.Count != rootParamCount)
|
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.");
|
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.
|
// 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;
|
IDxcBlob* reflectionBlob = default;
|
||||||
|
CBufferInfo cbufferInfo = default;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: This does not include generated code. This will cause a root signature mismatch.
|
// TODO: This does not include generated code. This will cause a root signature mismatch.
|
||||||
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow();
|
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow();
|
||||||
|
|
||||||
#if false
|
|
||||||
if (reflectionBlob != null)
|
if (reflectionBlob != null)
|
||||||
{
|
{
|
||||||
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
|
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
|
||||||
ValidateReflectionData(reflection);
|
cbufferInfo = ValidateReflectionData(descriptor, reflection);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -266,7 +267,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = descriptor.defines.AsSpan(),
|
defines = descriptor.defines.AsSpan(),
|
||||||
includes = descriptor.includes.AsSpan(),
|
include = descriptor.generatedCodePath,
|
||||||
shaderPath = tsEntry.shader,
|
shaderPath = tsEntry.shader,
|
||||||
entryPoint = tsEntry.entry,
|
entryPoint = tsEntry.entry,
|
||||||
stage = ShaderStage.TaskShader,
|
stage = ShaderStage.TaskShader,
|
||||||
@@ -275,7 +276,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
options = CompilerOption.KeepReflections,
|
options = CompilerOption.KeepReflections,
|
||||||
};
|
};
|
||||||
|
|
||||||
tsResult = CompileAndValidate(ref config);
|
tsResult = CompileAndValidate(ref config, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileResult msResult;
|
CompileResult msResult;
|
||||||
@@ -285,7 +286,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = descriptor.defines.AsSpan(),
|
defines = descriptor.defines.AsSpan(),
|
||||||
includes = descriptor.includes.AsSpan(),
|
include = descriptor.generatedCodePath,
|
||||||
shaderPath = msEntry.shader,
|
shaderPath = msEntry.shader,
|
||||||
entryPoint = msEntry.entry,
|
entryPoint = msEntry.entry,
|
||||||
stage = ShaderStage.MeshShader,
|
stage = ShaderStage.MeshShader,
|
||||||
@@ -294,11 +295,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
options = CompilerOption.KeepReflections,
|
options = CompilerOption.KeepReflections,
|
||||||
};
|
};
|
||||||
|
|
||||||
msResult = CompileAndValidate(ref config);
|
msResult = CompileAndValidate(ref config, descriptor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Result<D3D12GraphicsCompiledResult>.Fail("Mesh shader expected.");
|
throw new InvalidOperationException("Mesh shader expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileResult psResult;
|
CompileResult psResult;
|
||||||
@@ -308,7 +309,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = descriptor.defines.AsSpan(),
|
defines = descriptor.defines.AsSpan(),
|
||||||
includes = descriptor.includes.AsSpan(),
|
include = descriptor.generatedCodePath,
|
||||||
shaderPath = psEntry.shader,
|
shaderPath = psEntry.shader,
|
||||||
entryPoint = psEntry.entry,
|
entryPoint = psEntry.entry,
|
||||||
stage = ShaderStage.PixelShader,
|
stage = ShaderStage.PixelShader,
|
||||||
@@ -317,11 +318,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
options = CompilerOption.KeepReflections,
|
options = CompilerOption.KeepReflections,
|
||||||
};
|
};
|
||||||
|
|
||||||
psResult = CompileAndValidate(ref config);
|
psResult = CompileAndValidate(ref config, descriptor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Result<D3D12GraphicsCompiledResult>.Fail("Pixel shader expected.");
|
throw new InvalidOperationException("Pixel shader expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new D3D12GraphicsCompiledResult
|
return new D3D12GraphicsCompiledResult
|
||||||
@@ -353,6 +354,11 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
return D3D12Utility.D3D12_DEPTH_STENCIL_DESC_CREATE(depthEnabled, writeEnabled, cmp);
|
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)
|
private GraphicsPipelineKey CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly D3D12GraphicsCompiledResult compiled)
|
||||||
{
|
{
|
||||||
var rtvCount = (uint)Math.Min(descriptor.rtvFormats.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
|
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);
|
ref var existing = ref CollectionsMarshal.GetValueRefOrAddDefault(_pipelineCache, key, out var exists);
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
existing.compileResult = compiled;
|
|
||||||
existing.psoDesc = desc;
|
existing.psoDesc = desc;
|
||||||
|
|
||||||
var meshStream = new CD3DX12_PIPELINE_MESH_STATE_STREAM(in 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)
|
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)
|
switch (descriptor)
|
||||||
{
|
{
|
||||||
case FullPassDescriptor fullPass:
|
case FullPassDescriptor fullPass:
|
||||||
var result = CompileAndValidateFullPass(fullPass).GetValueOrThrow();
|
if (!hasCompiledCache)
|
||||||
|
{
|
||||||
|
compiled = CompileAndValidateFullPass(fullPass);
|
||||||
|
}
|
||||||
|
|
||||||
var psoDes = new GraphicsPSODescriptor
|
var psoDes = new GraphicsPSODescriptor
|
||||||
{
|
{
|
||||||
passId = new(fullPass.Identifier),
|
passId = new ShaderPassKey(fullPass.Identifier),
|
||||||
zTest = fullPass.localPipeline.zTest,
|
zTest = fullPass.localPipeline.zTest,
|
||||||
zWrite = fullPass.localPipeline.zWrite,
|
zWrite = fullPass.localPipeline.zWrite,
|
||||||
cull = fullPass.localPipeline.cull,
|
cull = fullPass.localPipeline.cull,
|
||||||
@@ -466,10 +479,17 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
dsvFormat = dsv,
|
dsvFormat = dsv,
|
||||||
};
|
};
|
||||||
|
|
||||||
key = CompilePSO(in psoDes, in result);
|
key = CompilePSO(in psoDes, in compiled);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Do we need to support other pass types?
|
// 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:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -478,15 +498,24 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
return key;
|
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 (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||||
if (Unsafe.IsNullRef(ref 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()
|
public void Dispose()
|
||||||
|
|||||||
@@ -210,6 +210,13 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
clearStencil = 0,
|
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);
|
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
||||||
|
|
||||||
var viewport = new ViewportDesc { width = _currentSize.x, height = _currentSize.y, minDepth = 0, maxDepth = 1 };
|
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);
|
cmd.SetScissorRect(scissor);
|
||||||
|
|
||||||
// NOTE: Testing only.
|
// NOTE: Testing only.
|
||||||
var ctx = new RenderingContext(_graphicsEngine, cmd, _graphicsEngine.CopyCommandBuffer, null!);
|
|
||||||
if (_frameIndex == 0)
|
|
||||||
{
|
|
||||||
_pass.Initialize(ref ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pass.Execute(ref ctx);
|
_pass.Execute(ref ctx);
|
||||||
|
|
||||||
cmd.EndRenderPass();
|
cmd.EndRenderPass();
|
||||||
|
|||||||
@@ -597,13 +597,19 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||||
|
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||||
|
|
||||||
private ComPtr<D3D12MA_Allocator> _allocator;
|
private ComPtr<D3D12MA_Allocator> _allocator;
|
||||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
||||||
|
|
||||||
private bool _disposed;
|
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
|
var desc = new D3D12MA_ALLOCATOR_DESC
|
||||||
{
|
{
|
||||||
@@ -616,10 +622,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
||||||
_allocator.Attach(pAllocator);
|
_allocator.Attach(pAllocator);
|
||||||
|
|
||||||
_device = device;
|
|
||||||
_fenceSynchronizer = fenceSynchronizer;
|
_fenceSynchronizer = fenceSynchronizer;
|
||||||
|
_device = device;
|
||||||
_descriptorAllocator = descriptorAllocator;
|
_descriptorAllocator = descriptorAllocator;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
_pipelineLibrary = pipelineLibrary;
|
||||||
|
|
||||||
_temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
_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)
|
public Identifier<Shader> CreateShader(ShaderDescriptor descriptor)
|
||||||
{
|
{
|
||||||
var shader = new Shader(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);
|
return _resourceDatabase.AddShader(shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
using static TerraFX.Interop.DirectX.DXC;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
internal struct CompileResult : IDisposable
|
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
|
internal readonly struct ResourceBindingInfo
|
||||||
{
|
{
|
||||||
public string Name
|
public string Name
|
||||||
@@ -145,10 +99,10 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
{
|
{
|
||||||
return level switch
|
return level switch
|
||||||
{
|
{
|
||||||
CompilerOptimizeLevel.O0 => "-O0",
|
CompilerOptimizeLevel.O0 => DXC_ARG_OPTIMIZATION_LEVEL0,
|
||||||
CompilerOptimizeLevel.O1 => "-O1",
|
CompilerOptimizeLevel.O1 => DXC_ARG_OPTIMIZATION_LEVEL1,
|
||||||
CompilerOptimizeLevel.O2 => "-O2",
|
CompilerOptimizeLevel.O2 => DXC_ARG_OPTIMIZATION_LEVEL2,
|
||||||
CompilerOptimizeLevel.O3 => "-O3",
|
CompilerOptimizeLevel.O3 => DXC_ARG_OPTIMIZATION_LEVEL3,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(level), "Unsupported optimization level")
|
_ => throw new ArgumentOutOfRangeException(nameof(level), "Unsupported optimization level")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -164,18 +118,20 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
GetOptimizeLevelString(config.optimizeLevel), // Optimization level
|
GetOptimizeLevelString(config.optimizeLevel), // Optimization level
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var include in config.includes)
|
|
||||||
{
|
|
||||||
argsArray.Add("-I");
|
|
||||||
argsArray.Add(include);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var define in config.defines)
|
foreach (var define in config.defines)
|
||||||
{
|
{
|
||||||
argsArray.Add("-D");
|
argsArray.Add("-D");
|
||||||
argsArray.Add(define);
|
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))
|
if (!config.options.HasFlag(CompilerOption.KeepDebugInfo))
|
||||||
{
|
{
|
||||||
argsArray.Add("-Qstrip_debug");
|
argsArray.Add("-Qstrip_debug");
|
||||||
@@ -188,7 +144,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
|
|
||||||
if (config.options.HasFlag(CompilerOption.WarnAsError))
|
if (config.options.HasFlag(CompilerOption.WarnAsError))
|
||||||
{
|
{
|
||||||
argsArray.Add("-WX");
|
argsArray.Add(DXC_ARG_WARNINGS_ARE_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
return argsArray;
|
return argsArray;
|
||||||
@@ -210,8 +166,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
ThrowIfFailed(DxcCreateInstance(&dxccID, __uuidof(pCompiler), (void**)&pCompiler));
|
ThrowIfFailed(DxcCreateInstance(&dxccID, __uuidof(pCompiler), (void**)&pCompiler));
|
||||||
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
|
ThrowIfFailed(DxcCreateInstance(&dxcuID, __uuidof(pUtils), (void**)&pUtils));
|
||||||
|
|
||||||
//pIncludeHandler.Get()->LoadSource();
|
ThrowIfFailed(pUtils->CreateDefaultIncludeHandler(&pIncludeHandler));
|
||||||
pUtils->CreateDefaultIncludeHandler(&pIncludeHandler);
|
|
||||||
|
|
||||||
// Create source blob
|
// Create source blob
|
||||||
using ComPtr<IDxcBlobEncoding> sourceBlob = default;
|
using ComPtr<IDxcBlobEncoding> sourceBlob = default;
|
||||||
@@ -239,7 +194,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
{
|
{
|
||||||
Ptr = sourceBlob.Get()->GetBufferPointer(),
|
Ptr = sourceBlob.Get()->GetBufferPointer(),
|
||||||
Size = sourceBlob.Get()->GetBufferSize(),
|
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));
|
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;
|
using ComPtr<IDxcBlob> bytecodeBlob = default;
|
||||||
ThrowIfFailed(pResult->GetResult(bytecodeBlob.GetAddressOf()));
|
ThrowIfFailed(pResult->GetResult(bytecodeBlob.GetAddressOf()));
|
||||||
|
|
||||||
// Get reflection data using DXC API
|
// Get pReflection data using DXC API
|
||||||
if (ppReflectionBlob != null)
|
if (ppReflectionBlob != null)
|
||||||
{
|
{
|
||||||
ThrowIfFailed(pResult->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof<IDxcBlob>(), (void**)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: 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 reflection data instead of populating raw lists/dictionaries.
|
// TODO: Ideally this should return a structured pReflection data instead of populating raw lists/dictionaries.
|
||||||
public static Result<ShaderReflectionData> PerformDXCReflection(IDxcBlob* reflectionBlob)
|
public static Result<ShaderReflectionData> PerformDXCReflection(IDxcBlob* reflectionBlob)
|
||||||
{
|
{
|
||||||
if (reflectionBlob == null)
|
if (reflectionBlob == null)
|
||||||
@@ -311,34 +266,34 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
return Result<ShaderReflectionData>.Fail("Reflection blob is null.");
|
return Result<ShaderReflectionData>.Fail("Reflection blob is null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<IDxcUtils> utils = default;
|
IDxcUtils* pUtils = default;
|
||||||
ComPtr<ID3D12ShaderReflection> reflection = default;
|
ID3D12ShaderReflection* pReflection = default;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create DXC pUtils to parse reflection data
|
// Create DXC pUtils to parse pReflection data
|
||||||
var dxcuID = CLSID.CLSID_DxcUtils;
|
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
|
var reflectionBuffer = new DxcBuffer
|
||||||
{
|
{
|
||||||
Ptr = reflectionBlob->GetBufferPointer(),
|
Ptr = reflectionBlob->GetBufferPointer(),
|
||||||
Size = reflectionBlob->GetBufferSize(),
|
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;
|
D3D12_SHADER_DESC shaderDesc;
|
||||||
ThrowIfFailed(reflection.Get()->GetDesc(&shaderDesc));
|
ThrowIfFailed(pReflection->GetDesc(&shaderDesc));
|
||||||
|
|
||||||
var reflectionData = new ShaderReflectionData();
|
var reflectionData = new ShaderReflectionData();
|
||||||
|
|
||||||
for (uint i = 0; i < shaderDesc.BoundResources; i++)
|
for (uint i = 0; i < shaderDesc.BoundResources; i++)
|
||||||
{
|
{
|
||||||
D3D12_SHADER_INPUT_BIND_DESC bindDesc;
|
D3D12_SHADER_INPUT_BIND_DESC bindDesc;
|
||||||
ThrowIfFailed(reflection.Get()->GetResourceBindingDesc(i, &bindDesc));
|
ThrowIfFailed(pReflection->GetResourceBindingDesc(i, &bindDesc));
|
||||||
|
|
||||||
var resourceName = Marshal.PtrToStringUTF8((IntPtr)bindDesc.Name);
|
var resourceName = Marshal.PtrToStringUTF8((IntPtr)bindDesc.Name);
|
||||||
if (resourceName == null)
|
if (resourceName == null)
|
||||||
@@ -350,11 +305,11 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
{
|
{
|
||||||
case D3D_SHADER_INPUT_TYPE.D3D_SIT_CBUFFER:
|
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;
|
D3D12_SHADER_BUFFER_DESC cbufferDesc;
|
||||||
ThrowIfFailed(cbuffer->GetDesc(&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
|
// Now we iterate all variables for *every* cbuffer, not just b3
|
||||||
for (uint j = 0; j < cbufferDesc.Variables; j++)
|
for (uint j = 0; j < cbufferDesc.Variables; j++)
|
||||||
@@ -369,7 +324,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
variables.Add(new CBufferVariableInfo
|
variables.Add(new CBufferPropertyInfo
|
||||||
{
|
{
|
||||||
Name = variableName,
|
Name = variableName,
|
||||||
StartOffset = varDesc.StartOffset,
|
StartOffset = varDesc.StartOffset,
|
||||||
@@ -383,7 +338,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
RegisterSlot = bindDesc.BindPoint,
|
RegisterSlot = bindDesc.BindPoint,
|
||||||
RegisterSpace = bindDesc.Space,
|
RegisterSpace = bindDesc.Space,
|
||||||
SizeInBytes = cbufferDesc.Size,
|
SizeInBytes = cbufferDesc.Size,
|
||||||
Variables = variables
|
Properties = variables
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -411,8 +366,8 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
utils.Dispose();
|
pUtils->Release();
|
||||||
reflection.Dispose();
|
pReflection->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Misaki.HighPerformance.Utilities;
|
using Misaki.HighPerformance.Utilities;
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -122,6 +122,51 @@ public ref struct GraphicsPSODescriptor
|
|||||||
public TextureFormat dsvFormat;
|
public TextureFormat dsvFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly struct CBufferPropertyInfo
|
||||||
|
{
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StartOffset
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Size
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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<CBufferPropertyInfo> Properties
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct ViewportDesc
|
public struct ViewportDesc
|
||||||
{
|
{
|
||||||
@@ -685,8 +730,8 @@ public enum PrimitiveTopology
|
|||||||
|
|
||||||
internal ref struct CompilerConfig
|
internal ref struct CompilerConfig
|
||||||
{
|
{
|
||||||
public ReadOnlySpan<string> includes;
|
|
||||||
public ReadOnlySpan<string> defines;
|
public ReadOnlySpan<string> defines;
|
||||||
|
public string? include;
|
||||||
public string shaderPath;
|
public string shaderPath;
|
||||||
public string entryPoint;
|
public string entryPoint;
|
||||||
public ShaderStage stage;
|
public ShaderStage stage;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
|
|
||||||
public void Initialize(ref readonly RenderingContext ctx)
|
public void Initialize(ref readonly RenderingContext ctx)
|
||||||
{
|
{
|
||||||
var shaderDescriptor = SDLCompiler.CompileShader("F:\\csharp\\GhostEngine\\Ghost.Graphics\\test.gshader").GetValueOrThrow();
|
var shaderDescriptor = SDLCompiler.CompileShader("F:/csharp/GhostEngine/Ghost.Graphics/test.gshader", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
|
||||||
|
|
||||||
var key = ctx.PipelineLibrary.CompilePassPSO(shaderDescriptor.passes[0], [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown);
|
var key = ctx.PipelineLibrary.CompilePassPSO(shaderDescriptor.passes[0], [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown);
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
cbuffer ConstantBuffer : register(b0)
|
|
||||||
{
|
#include GENERATED_CODE_PATH
|
||||||
float4 _Color;
|
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Properties.hlsl"
|
||||||
uint _TextureIndex1;
|
|
||||||
uint _TextureIndex2;
|
|
||||||
uint _TextureIndex3;
|
|
||||||
uint _TextureIndex4;
|
|
||||||
uint _VertexBufferIndex;
|
|
||||||
uint _IndexBufferIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
@@ -34,8 +27,8 @@ void MSMain(
|
|||||||
out indices uint3 outTris[1])
|
out indices uint3 outTris[1])
|
||||||
{
|
{
|
||||||
// Fetch bindless buffers
|
// Fetch bindless buffers
|
||||||
ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[_VertexBufferIndex];
|
ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerMaterialData.vertexBufferIndex];
|
||||||
ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[_IndexBufferIndex];
|
ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerMaterialData.indexBufferIndex];
|
||||||
|
|
||||||
// Compute the triangle’s vertex indices
|
// Compute the triangle’s vertex indices
|
||||||
uint vertexId = groupThreadID.x;
|
uint vertexId = groupThreadID.x;
|
||||||
@@ -67,11 +60,11 @@ void MSMain(
|
|||||||
|
|
||||||
float4 PSMain(PixelInput input) : SV_TARGET
|
float4 PSMain(PixelInput input) : SV_TARGET
|
||||||
{
|
{
|
||||||
float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(_TextureIndex1, 0, input.uv.xy);
|
float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy);
|
||||||
float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(_TextureIndex2, 0, input.uv.xy);
|
float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy);
|
||||||
float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(_TextureIndex3, 0, input.uv.xy);
|
float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy);
|
||||||
float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(_TextureIndex4, 0, input.uv.xy);
|
float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy);
|
||||||
|
|
||||||
float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
||||||
return blendedColor * _Color;
|
return blendedColor * g_PerMaterialData.color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ shader "MyShader/Standard"
|
|||||||
tex2d_b texture2 = tex2d_b(white);
|
tex2d_b texture2 = tex2d_b(white);
|
||||||
tex2d_b texture3 = tex2d_b(grey);
|
tex2d_b texture3 = tex2d_b(grey);
|
||||||
tex2d_b texture4 = tex2d_b(normal);
|
tex2d_b texture4 = tex2d_b(normal);
|
||||||
|
uint vertexBufferIndex;
|
||||||
|
uint indexBufferIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline
|
pipeline
|
||||||
@@ -22,10 +24,5 @@ shader "MyShader/Standard"
|
|||||||
{
|
{
|
||||||
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
||||||
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
||||||
|
|
||||||
includes
|
|
||||||
{
|
|
||||||
"F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#ifndef COMMON_HLSL
|
#ifndef COMMON_HLSL
|
||||||
#define COMMON_HLSL
|
#define COMMON_HLSL
|
||||||
|
|
||||||
#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
|
#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
|
||||||
@@ -43,11 +43,11 @@
|
|||||||
#define STRUCT_BUFFER_BINDLESS uint
|
#define STRUCT_BUFFER_BINDLESS uint
|
||||||
#define BYTE_ADDRESS_BUFFER_BINDLESS uint
|
#define BYTE_ADDRESS_BUFFER_BINDLESS uint
|
||||||
|
|
||||||
#define TEXTURE2D Texture2D<float4>
|
#define TEXTURE2D Texture2D
|
||||||
#define TEXTURE3D Texture3D<float4>
|
#define TEXTURE3D Texture3D
|
||||||
#define TEXTURECUBE TextureCube<float4>
|
#define TEXTURECUBE TextureCube
|
||||||
#define TEXTURE2D_ARRAY Texture2DArray<float4>
|
#define TEXTURE2D_ARRAY Texture2DArray
|
||||||
#define TEXTURECUBE_ARRAY TextureCubeArray<float4>
|
#define TEXTURECUBE_ARRAY TextureCubeArray
|
||||||
|
|
||||||
#define SAMPLER SamplerState
|
#define SAMPLER SamplerState
|
||||||
|
|
||||||
@@ -69,11 +69,26 @@
|
|||||||
|
|
||||||
#define SAMPLE_TEXTURE2D(tex, samp, uv) tex.Sample(samp, uv)
|
#define SAMPLE_TEXTURE2D(tex, samp, uv) tex.Sample(samp, uv)
|
||||||
#define SAMPLE_TEXTURE2D_LEVEL(tex, samp, uv, level) tex.SampleLevel(samp, uv, level)
|
#define SAMPLE_TEXTURE2D_LEVEL(tex, samp, uv, level) tex.SampleLevel(samp, uv, level)
|
||||||
#define SAMPLE_TEXTURE2D_BINDLESS(texId, sampId, uv) GET_TEXTURE2D_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv)
|
#define SAMPLE_TEXTURE2D_BINDLESS(texId, sampId, uv) SampleTexture2DBindless(texId, sampId, uv)
|
||||||
#define SAMPLE_TEXTURE2D_LEVEL_BINDLESS(texId, sampId, uv, level) GET_TEXTURE2D_BINDLESS(texId).SampleLevel(GET_BINDLESS_SAMPLER(sampId), uv, level)
|
#define SAMPLE_TEXTURE2D_LEVEL_BINDLESS(texId, sampId, uv, level) SampleTexture2DLevelBindless(texId, sampId, uv, level)
|
||||||
|
|
||||||
#define SAMPLE_TEXTURE2D_ARRAY(tex, samp, uv, index) tex.Sample(samp, uv, index)
|
#define SAMPLE_TEXTURE2D_ARRAY(tex, samp, uv, index) tex.Sample(samp, uv, index)
|
||||||
#define SAMPLE_TEXTURE2D_ARRAY_BINDLESS(texId, sampId, uv, index) GET_TEXTURE2D_ARRAY_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv, index)
|
#define SAMPLE_TEXTURE2D_ARRAY_BINDLESS(texId, sampId, uv, index) GET_TEXTURE2D_ARRAY_BINDLESS(texId).Sample(GET_SAMPLER_BINDLESS(sampId), uv, index)
|
||||||
|
|
||||||
|
static inline float4 SampleTexture2DBindless(uint texId, uint sampId, float2 uv)
|
||||||
|
{
|
||||||
|
Texture2D tex = GET_TEXTURE2D_BINDLESS(texId);
|
||||||
|
SamplerState samp = GET_SAMPLER_BINDLESS(sampId);
|
||||||
|
return tex.Sample(samp, uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float4 SampleTexture2DLevelBindless(uint texId, uint sampId, float2 uv, float level)
|
||||||
|
{
|
||||||
|
Texture2D tex = GET_TEXTURE2D_BINDLESS(texId);
|
||||||
|
SamplerState samp = GET_SAMPLER_BINDLESS(sampId);
|
||||||
|
return tex.SampleLevel(samp, uv, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#ifndef PROPERTIES_HLSL
|
#ifndef PROPERTIES_HLSL
|
||||||
#define PROPERTIES_HLSL
|
#define PROPERTIES_HLSL
|
||||||
|
|
||||||
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"
|
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public struct SDLError
|
|||||||
public int line;
|
public int line;
|
||||||
public int column;
|
public int column;
|
||||||
|
|
||||||
public readonly override string ToString()
|
public override readonly string ToString()
|
||||||
{
|
{
|
||||||
return $"Error at {line}:{column} - {message}";
|
return $"Error at {line}:{column} - {message}";
|
||||||
}
|
}
|
||||||
@@ -125,24 +125,6 @@ internal static class SDLCompiler
|
|||||||
|
|
||||||
private static string GetPassUniqueId(SDLSemantics shader, PassSemantic pass)
|
private static string GetPassUniqueId(SDLSemantics shader, PassSemantic pass)
|
||||||
{
|
{
|
||||||
//static ulong Fnv1a64(ReadOnlySpan<char> data)
|
|
||||||
//{
|
|
||||||
// const ulong offset = 14695981039346656037;
|
|
||||||
// const ulong prime = 1099511628211;
|
|
||||||
|
|
||||||
// var hash = offset;
|
|
||||||
|
|
||||||
// foreach (var b in data)
|
|
||||||
// {
|
|
||||||
// hash ^= b;
|
|
||||||
// hash *= prime;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return hash;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//return $"{Fnv1a64(shader.name)}_{pass.name}";
|
|
||||||
|
|
||||||
return $"{shader.name}_{pass.name}";
|
return $"{shader.name}_{pass.name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +197,7 @@ internal static class SDLCompiler
|
|||||||
|
|
||||||
if (shaderGlobalProperties != null)
|
if (shaderGlobalProperties != null)
|
||||||
{
|
{
|
||||||
|
descriptor.globalProperties ??= new List<PropertyDescriptor>();
|
||||||
descriptor.globalProperties.AddRange(shaderGlobalProperties);
|
descriptor.globalProperties.AddRange(shaderGlobalProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,27 +228,49 @@ internal static class SDLCompiler
|
|||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result<ShaderDescriptor> CompileShader(string shaderPath)
|
public static Result<ShaderDescriptor> CompileShader(string shaderPath, string generatedOutputDirectory)
|
||||||
{
|
{
|
||||||
var source = File.ReadAllText(shaderPath);
|
try
|
||||||
|
|
||||||
var lexer = new Lexer(source);
|
|
||||||
var stream = new TokenStream(lexer.Tokenize());
|
|
||||||
var shaderInfo = ParseShaders(stream);
|
|
||||||
var model = SemanticAnalysis(shaderInfo[0], out var errors);
|
|
||||||
|
|
||||||
if (errors.Count != 0 || model == null)
|
|
||||||
{
|
{
|
||||||
var errorMessages = new StringBuilder();
|
var source = File.ReadAllText(shaderPath);
|
||||||
foreach (var error in errors)
|
|
||||||
|
var lexer = new Lexer(source);
|
||||||
|
var stream = new TokenStream(lexer.Tokenize());
|
||||||
|
var shaderInfo = ParseShaders(stream);
|
||||||
|
var model = SemanticAnalysis(shaderInfo[0], out var errors);
|
||||||
|
|
||||||
|
if (errors.Count != 0 || model == null)
|
||||||
{
|
{
|
||||||
errorMessages.AppendLine(error.ToString());
|
var errorMessages = new StringBuilder();
|
||||||
|
foreach (var error in errors)
|
||||||
|
{
|
||||||
|
errorMessages.AppendLine(error.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Fail("Failed to compile shader due to errors:\n" + errorMessages.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result<ShaderDescriptor>.Fail("Failed to compile shader due to errors:\n" + errorMessages.ToString());
|
var desc = ResolveShader(model);
|
||||||
}
|
var globalPropPath = GenerateGlobalProperties(desc.globalProperties, generatedOutputDirectory);
|
||||||
|
|
||||||
return ResolveShader(model);
|
foreach (var pass in desc.passes)
|
||||||
|
{
|
||||||
|
if (pass is not FullPassDescriptor fullPass)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullPass.includes ??= new List<string>();
|
||||||
|
fullPass.includes.Add(globalPropPath);
|
||||||
|
fullPass.generatedCodePath = GeneratePass(fullPass, generatedOutputDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail("Failed to generate shader files: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ShaderPropertyTypeToHLSLType(ShaderPropertyType type)
|
private static string ShaderPropertyTypeToHLSLType(ShaderPropertyType type)
|
||||||
@@ -330,6 +335,16 @@ internal static class SDLCompiler
|
|||||||
#define {fileDefine}
|
#define {fileDefine}
|
||||||
|
|
||||||
#include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl""");
|
#include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl""");
|
||||||
|
if (fullPass.includes != null)
|
||||||
|
{
|
||||||
|
foreach (var include in fullPass.includes)
|
||||||
|
{
|
||||||
|
sb.Append($@"
|
||||||
|
#include ""{include}""");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
if (fullPass.properties != null)
|
if (fullPass.properties != null)
|
||||||
{
|
{
|
||||||
@@ -354,23 +369,20 @@ struct PerMaterialData
|
|||||||
return outputFilePath;
|
return outputFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GenerateShader(ShaderDescriptor descriptor, string targetDirectory)
|
public static string GenerateGlobalProperties(List<PropertyDescriptor> globalProperties, string targetDirectory)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(targetDirectory))
|
if (!Directory.Exists(targetDirectory))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Target directory does not exist.", nameof(targetDirectory));
|
throw new ArgumentException("Target directory does not exist.", nameof(targetDirectory));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate global property file.
|
var globalFilePath = Path.Combine(targetDirectory, _GLOBAL_PROPERTY_FILE_NAME);
|
||||||
if (descriptor.globalProperties.Count > 0)
|
using var globalFileStream = File.CreateText(globalFilePath);
|
||||||
{
|
|
||||||
var globalFilePath = Path.Combine(targetDirectory, _GLOBAL_PROPERTY_FILE_NAME);
|
|
||||||
using var globalFileStream = File.CreateText(globalFilePath);
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
sb.AppendLine(_GENERATED_FILE_HEADER);
|
sb.AppendLine(_GENERATED_FILE_HEADER);
|
||||||
sb.Append(@"
|
sb.Append(@"
|
||||||
#ifndef GLOBALDATA_G_HLSL
|
#ifndef GLOBALDATA_G_HLSL
|
||||||
#define GLOBALDATA_G_HLSL
|
#define GLOBALDATA_G_HLSL
|
||||||
|
|
||||||
@@ -378,22 +390,17 @@ struct PerMaterialData
|
|||||||
|
|
||||||
struct GlobalData
|
struct GlobalData
|
||||||
{");
|
{");
|
||||||
foreach (var prop in descriptor.globalProperties)
|
foreach (var prop in globalProperties)
|
||||||
{
|
{
|
||||||
sb.Append($@"
|
sb.Append($@"
|
||||||
{ShaderPropertyTypeToHLSLType(prop.type)} {prop.name};");
|
{ShaderPropertyTypeToHLSLType(prop.type)} {prop.name};");
|
||||||
}
|
}
|
||||||
sb.AppendLine(@"
|
sb.AppendLine(@"
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GLOBALDATA_G_HLSL");
|
#endif // GLOBALDATA_G_HLSL");
|
||||||
globalFileStream.Write(sb.ToString());
|
globalFileStream.Write(sb.ToString());
|
||||||
}
|
|
||||||
|
|
||||||
// Compile each pass.
|
return globalFilePath;
|
||||||
foreach (var pass in descriptor.passes)
|
|
||||||
{
|
|
||||||
GeneratePass(pass, targetDirectory);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,6 +274,7 @@ struct {structName}
|
|||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine(@$"// Auto-generated HLSL code, please do not edit this file directly.
|
sb.AppendLine(@$"// Auto-generated HLSL code, please do not edit this file directly.
|
||||||
|
|
||||||
#ifndef {hlslDefine}
|
#ifndef {hlslDefine}
|
||||||
#define {hlslDefine}");
|
#define {hlslDefine}");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user