Refactor and enhance rendering pipeline
- Added new C# formatting rules in .editorconfig. - Introduced `IKeyType`, `Key<T>`, and `Ptr<T>` structs. - Updated `Result` and `Result<T>` for implicit conversions. - Added AOT compatibility to project files. - Introduced a `Camera` class and refactored namespaces. - Enhanced rendering with bindless support and pipeline state management. - Refactored `D3D12CommandBuffer` for new rendering features. - Improved `D3D12PipelineLibrary` with disk caching methods. - Added support for UAVs and raw buffers in `D3D12ResourceAllocator`. - Improved shader compilation and reflection in `D3D12ShaderCompiler`. - Refactored descriptor heap and swap chain initialization. - Added enums and structs for rendering configurations. - Expanded `ICommandBuffer` and `IPipelineLibrary` interfaces. - Updated `MeshRenderPass` to align with the new pipeline. - Consolidated namespaces and improved code maintainability.
This commit is contained in:
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[*.cs]
|
||||||
|
csharp_new_line_before_open_brace = all
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
dotnet_sort_system_directives_first = false
|
||||||
|
dotnet_separate_import_directive_groups = false
|
||||||
|
max_line_length = 400
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
public interface IHandleType;
|
public interface IHandleType;
|
||||||
public interface IIdentifierType;
|
public interface IIdentifierType;
|
||||||
|
public interface IKeyType;
|
||||||
|
|
||||||
public readonly struct Handle<T>
|
public readonly struct Handle<T>
|
||||||
where T : IHandleType
|
where T : IHandleType
|
||||||
@@ -93,4 +94,49 @@ public readonly struct Identifier<T>
|
|||||||
{
|
{
|
||||||
return !a.Equals(b);
|
return !a.Equals(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly struct Key<T>
|
||||||
|
where T : IKeyType
|
||||||
|
{
|
||||||
|
public readonly ulong value;
|
||||||
|
|
||||||
|
public Key(ulong value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Key<T> Invalid => new(0);
|
||||||
|
|
||||||
|
public bool IsValid => this != Invalid;
|
||||||
|
|
||||||
|
public readonly override int GetHashCode()
|
||||||
|
{
|
||||||
|
return value.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Key<T> id && Equals(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly bool Equals(Key<T> other)
|
||||||
|
{
|
||||||
|
return value == other.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly int CompareTo(Key<T> other)
|
||||||
|
{
|
||||||
|
return value.CompareTo(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Key<T> a, Key<T> b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Key<T> a, Key<T> b)
|
||||||
|
{
|
||||||
|
return !a.Equals(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
27
Ghost.Core/Ptr.cs
Normal file
27
Ghost.Core/Ptr.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Ghost.Core;
|
||||||
|
|
||||||
|
public unsafe readonly struct Ptr<T>
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
public readonly T* value;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ptr(T* value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator T*(Ptr<T> ptr)
|
||||||
|
{
|
||||||
|
return ptr.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator Ptr<T>(T* value)
|
||||||
|
{
|
||||||
|
return new Ptr<T>(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public readonly struct Result
|
|||||||
|
|
||||||
public override string ToString() => success ? "OK" : $"Error: {message}";
|
public override string ToString() => success ? "OK" : $"Error: {message}";
|
||||||
|
|
||||||
public static implicit operator Result(bool success) => success ? Success() : Fail(null);
|
public static implicit operator bool(Result result) => result.success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct Result<T>
|
public readonly struct Result<T>
|
||||||
@@ -54,6 +54,7 @@ public readonly struct Result<T>
|
|||||||
public override string ToString() => success ? $"OK: {value}" : $"Error: {message}";
|
public override string ToString() => success ? $"OK: {value}" : $"Error: {message}";
|
||||||
|
|
||||||
public static implicit operator Result<T>(T? data) => data is not null ? Success(data) : Fail(null);
|
public static implicit operator Result<T>(T? data) => data is not null ? Success(data) : Fail(null);
|
||||||
|
public static implicit operator Result<T>(Result result) => result.success ? Success(default!) : Fail(result.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ResultExtensions
|
public static class ResultExtensions
|
||||||
@@ -75,4 +76,4 @@ public static class ResultExtensions
|
|||||||
|
|
||||||
return result.value;
|
return result.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -7,33 +8,82 @@ namespace Ghost.Core.Utilities;
|
|||||||
|
|
||||||
#if PLATEFORME_WIN64
|
#if PLATEFORME_WIN64
|
||||||
[SupportedOSPlatform("windows10.0.19041.0")]
|
[SupportedOSPlatform("windows10.0.19041.0")]
|
||||||
internal unsafe static class Win32Utility
|
internal static unsafe class Win32Utility
|
||||||
{
|
{
|
||||||
public static Guid* IID_NULL => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID.IID_NULL));
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly ref struct IID_PPV
|
||||||
[Conditional("DEBUG")]
|
|
||||||
public static void Assert(this HRESULT hr)
|
|
||||||
{
|
{
|
||||||
Debug.Assert(hr.SUCCEEDED);
|
public readonly Guid* iid;
|
||||||
|
public readonly void** ppv;
|
||||||
|
|
||||||
|
public IID_PPV(Guid* iid, void** ppv)
|
||||||
|
{
|
||||||
|
this.iid = iid;
|
||||||
|
this.ppv = ppv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deconstruct(out Guid* iid, out void** ppv)
|
||||||
|
{
|
||||||
|
iid = this.iid;
|
||||||
|
ppv = this.ppv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Guid* IID_NULL
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in TerraFX.Interop.Windows.IID.IID_NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IID_PPV IID_PPV_ARGS<T>(ComPtr<T> comPtr)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
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")]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Assert(this HRESULT hr)
|
||||||
|
{
|
||||||
|
Debug.Assert(hr.SUCCEEDED, hr.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void ThrowIfFailed(this HRESULT hr)
|
public static void ThrowIfFailed(this HRESULT hr)
|
||||||
{
|
{
|
||||||
Windows.ThrowIfFailed(hr);
|
Windows.ThrowIfFailed(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void** GetVoidAddressOf<T>(this ComPtr<T> comPtr)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Guid* IID<T>(this ComPtr<T> comPtr)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return Windows.__uuidof<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void** PPV<T>(this ComPtr<T> comPtr)
|
||||||
where T : unmanaged, IUnknown.Interface
|
where T : unmanaged, IUnknown.Interface
|
||||||
{
|
{
|
||||||
return (void**)comPtr.GetAddressOf();
|
return (void**)comPtr.GetAddressOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void** ReleaseAndGetVoidAddressOf<T>(this ComPtr<T> comPtr)
|
public static void** ReleaseAndGetVoidAddressOf<T>(this ComPtr<T> comPtr)
|
||||||
where T : unmanaged, IUnknown.Interface
|
where T : unmanaged, IUnknown.Interface
|
||||||
{
|
{
|
||||||
return (void**)comPtr.ReleaseAndGetAddressOf();
|
return (void**)comPtr.ReleaseAndGetAddressOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ComPtr<T> Move<T>(ref this ComPtr<T> comPtr)
|
public static ComPtr<T> Move<T>(ref this ComPtr<T> comPtr)
|
||||||
where T : unmanaged, IUnknown.Interface
|
where T : unmanaged, IUnknown.Interface
|
||||||
{
|
{
|
||||||
@@ -42,10 +92,11 @@ internal unsafe static class Win32Utility
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool HasFlag<T>(this uint flags, T flag)
|
public static bool HasFlag<T>(this uint flags, T flag)
|
||||||
where T : Enum
|
where T : Enum
|
||||||
{
|
{
|
||||||
return (flags & Unsafe.As<T, uint>(ref flag)) != 0;
|
return (flags & Unsafe.As<T, uint>(ref flag)) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,14 @@
|
|||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Template\ForEach.cs">
|
<None Include="Template\ForEach.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="fmod.dll" />
|
<None Remove="fmod.dll" />
|
||||||
<None Remove="fmodstudio.dll" />
|
<None Remove="fmodstudio.dll" />
|
||||||
|
|||||||
5
Ghost.Graphics/Core/Camera.cs
Normal file
5
Ghost.Graphics/Core/Camera.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
|
public class Camera
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a color with 4 bytes components.
|
/// Represents a color with 4 bytes components.
|
||||||
@@ -111,4 +111,4 @@ public struct Color128 : IEquatable<Color128>
|
|||||||
{
|
{
|
||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ using Misaki.HighPerformance.LowLevel.Utilities;
|
|||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
internal struct CBufferCache : IResourceReleasable
|
internal struct CBufferCache : IResourceReleasable
|
||||||
{
|
{
|
||||||
@@ -214,4 +214,4 @@ public ref struct MaterialAccessor
|
|||||||
cmb.Upload(cache.GpuResource, cache.CpuData.AsSpan());
|
cmb.Upload(cache.GpuResource, cache.CpuData.AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ using Misaki.HighPerformance.LowLevel.Utilities;
|
|||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Mathematics.Geometry;
|
using Misaki.HighPerformance.Mathematics.Geometry;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public struct Mesh : IResourceReleasable, IHandleType
|
public struct Mesh : IResourceReleasable, IHandleType
|
||||||
{
|
{
|
||||||
@@ -169,4 +169,4 @@ public static class MeshExtension
|
|||||||
mesh.vertices[i].tangent = new float4(t.x, t.y, t.z, w);
|
mesh.vertices[i].tangent = new float4(t.x, t.y, t.z, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
using Ghost.Core.Graphics;
|
||||||
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 Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public unsafe readonly ref struct RenderingContext
|
public unsafe readonly ref struct RenderingContext
|
||||||
{
|
{
|
||||||
private readonly IRenderDevice _device;
|
private readonly IRenderDevice _device;
|
||||||
private readonly ICommandBuffer _cmd;
|
private readonly ICommandBuffer _directCmb;
|
||||||
private readonly ICommandBuffer _copyCmd;
|
private readonly ICommandBuffer _copyCmb;
|
||||||
private readonly ICommandBuffer _computeCmd;
|
private readonly ICommandBuffer _computeCmb;
|
||||||
private readonly IResourceAllocator _resourceAllocator;
|
private readonly IResourceAllocator _resourceAllocator;
|
||||||
private readonly IResourceDatabase _resourceDatabase;
|
private readonly IResourceDatabase _resourceDatabase;
|
||||||
private readonly IPipelineLibrary _stateController;
|
private readonly IPipelineLibrary _stateController;
|
||||||
|
|
||||||
internal RenderingContext(
|
internal RenderingContext(
|
||||||
IRenderDevice device,
|
IRenderDevice device,
|
||||||
ICommandBuffer cmd,
|
ICommandBuffer directCmd,
|
||||||
ICommandBuffer copyCmd,
|
ICommandBuffer copyCmd,
|
||||||
ICommandBuffer computeCmd,
|
ICommandBuffer computeCmd,
|
||||||
IResourceAllocator resourceAllocator,
|
IResourceAllocator resourceAllocator,
|
||||||
@@ -26,9 +27,9 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
IPipelineLibrary stateController)
|
IPipelineLibrary stateController)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
_cmd = cmd;
|
_directCmb = directCmd;
|
||||||
_copyCmd = copyCmd;
|
_copyCmb = copyCmd;
|
||||||
_computeCmd = computeCmd;
|
_computeCmb = computeCmd;
|
||||||
_resourceAllocator = resourceAllocator;
|
_resourceAllocator = resourceAllocator;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
_stateController = stateController;
|
_stateController = stateController;
|
||||||
@@ -51,6 +52,8 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
return CreateMesh(vertexList, indexList);
|
return CreateMesh(vertexList, indexList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make one memory pool for upload.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uploads the mesh data to the GPU.
|
/// Uploads the mesh data to the GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -66,29 +69,29 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_copyCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
||||||
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
|
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_copyCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
||||||
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), ResourceState.CopyDest);
|
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
_copyCmd.Upload(meshData.vertexBuffer, meshData.vertices.AsSpan());
|
_copyCmb.Upload(meshData.vertexBuffer, meshData.vertices.AsSpan());
|
||||||
_copyCmd.Upload(meshData.indexBuffer, meshData.indices.AsSpan());
|
_copyCmb.Upload(meshData.indexBuffer, meshData.indices.AsSpan());
|
||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_copyCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
||||||
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
|
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState);
|
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState);
|
||||||
_copyCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markMeshStatic)
|
if (markMeshStatic)
|
||||||
@@ -119,27 +122,65 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
{
|
{
|
||||||
_copyCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
_copyCmb.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
||||||
_resourceDatabase.SetResourceState(texture.AsResource(), ResourceState.CopyDest);
|
_resourceDatabase.SetResourceState(texture.AsResource(), ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
_copyCmd.Upload(texture, subresourceData);
|
_copyCmb.Upload(texture, subresourceData);
|
||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
{
|
{
|
||||||
_copyCmd.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
|
_copyCmb.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
|
||||||
_resourceDatabase.SetResourceState(texture.AsResource(), sateBefore);
|
_resourceDatabase.SetResourceState(texture.AsResource(), sateBefore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderMesh(Handle<Mesh> mesh, Handle<Material> material)
|
public void RenderMesh(Handle<Mesh> mesh, Handle<Material> material, string passName)
|
||||||
{
|
{
|
||||||
//_cmd.DrawMesh(mesh, material);
|
//_cmd.DrawMesh(mesh, material);
|
||||||
|
ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh);
|
||||||
|
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material);
|
||||||
|
var shader = _resourceDatabase.GetShaderReference(materialRef.Shader);
|
||||||
|
|
||||||
|
shader.TryGetPassKey(passName, out var passKey);
|
||||||
|
var hash = new GraphicsPipelineHash
|
||||||
|
{
|
||||||
|
id = passKey,
|
||||||
|
rtvCount = 1,
|
||||||
|
dsvFormat = TextureFormat.Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm;
|
||||||
|
var pipelineKey = hash.GetKey();
|
||||||
|
_directCmb.SetPipelineState(pipelineKey);
|
||||||
|
|
||||||
|
// FIX: Get valid root signature. In D3D12, we use fixed root signature layout for bindless rendering.
|
||||||
|
// However, our code should not assume that blindly. Each pipeline should have contained root signature info even if there are fixed.
|
||||||
|
// This ensures that future changes to root signature layout can be accommodated.
|
||||||
|
|
||||||
|
// for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
ref var cache = ref materialRef.GetPassCache((int)passKey.value);
|
||||||
|
_directCmb.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.
|
||||||
|
// TODO: Matbe handle the transitional bindless model?
|
||||||
|
#if false
|
||||||
|
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
|
||||||
|
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
||||||
|
#endif
|
||||||
|
_directCmb.SetPrimitiveTopology(PrimitiveTopology.Triangle);
|
||||||
|
|
||||||
|
// Draw without vertex/index buffers - use instanced drawing
|
||||||
|
// Each instance represents a triangle (3 vertices)
|
||||||
|
var triangleCount = (uint)meshRef.indices.Count / 3;
|
||||||
|
_directCmb.Draw(3, triangleCount, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteCopyCommands()
|
public void ExecuteCopyCommands()
|
||||||
{
|
{
|
||||||
_device.CopyQueue.Submit(_copyCmd);
|
_device.CopyQueue.Submit(_copyCmb);
|
||||||
_device.CopyQueue.WaitIdle();
|
_device.CopyQueue.WaitIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public readonly struct GPUResource : IHandleType;
|
public readonly struct GPUResource : IHandleType;
|
||||||
public readonly struct Texture : IHandleType;
|
public readonly struct Texture : IHandleType;
|
||||||
@@ -27,4 +27,4 @@ public static class ResourceHandleExtensions
|
|||||||
{
|
{
|
||||||
return new Handle<GraphicsBuffer>(resource.id, resource.generation);
|
return new Handle<GraphicsBuffer>(resource.id, resource.generation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public readonly struct TextureInfo
|
public readonly struct TextureInfo
|
||||||
{
|
{
|
||||||
@@ -142,7 +142,7 @@ public class Shader : IResourceReleasable, IIdentifierType
|
|||||||
return _passIDs[index];
|
return _passIDs[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetPassKey(string passName, out ShaderPassKey? passID)
|
public bool TryGetPassKey(string passName, out ShaderPassKey passID)
|
||||||
{
|
{
|
||||||
var index = _passLookup.GetValueOrDefault(passName, -1);
|
var index = _passLookup.GetValueOrDefault(passName, -1);
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
@@ -169,4 +169,4 @@ public class Shader : IResourceReleasable, IIdentifierType
|
|||||||
{
|
{
|
||||||
_passIDs.Dispose();
|
_passIDs.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Ghost.Graphics.Contracts;
|
using Ghost.Graphics.Contracts;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
internal readonly struct SwapChainPresenter
|
internal readonly struct SwapChainPresenter
|
||||||
{
|
{
|
||||||
@@ -51,4 +52,4 @@ internal readonly struct SwapChainPresenter
|
|||||||
Width = width;
|
Width = width;
|
||||||
Height = height;
|
Height = height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Data;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct Vertex
|
public struct Vertex
|
||||||
@@ -25,4 +26,4 @@ public struct Vertex
|
|||||||
public float4 tangent;
|
public float4 tangent;
|
||||||
public float4 uv;
|
public float4 uv;
|
||||||
public Color128 color;
|
public Color128 color;
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
using static TerraFX.Aliases.D3D_Alias;
|
|
||||||
using static TerraFX.Aliases.D3D12_Alias;
|
using static TerraFX.Aliases.D3D12_Alias;
|
||||||
|
using static TerraFX.Aliases.D3D_Alias;
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
|
using Ghost.Core.Graphics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
@@ -26,17 +27,26 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
private readonly D3D12ResourceAllocator _resourceAllocator;
|
private readonly D3D12ResourceAllocator _resourceAllocator;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
|
|
||||||
|
private string _name;
|
||||||
private readonly CommandBufferType _type;
|
private readonly CommandBufferType _type;
|
||||||
private ushort _commandCount;
|
private ushort _commandCount;
|
||||||
private bool _isRecording;
|
private bool _isRecording;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public CommandBufferType Type => _type;
|
|
||||||
|
|
||||||
public ID3D12GraphicsCommandList10* NativeCommandList => _commandList.Get();
|
public ID3D12GraphicsCommandList10* NativeCommandList => _commandList.Get();
|
||||||
|
public CommandBufferType Type => _type;
|
||||||
public bool IsEmpty => _commandCount == 0;
|
public bool IsEmpty => _commandCount == 0;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_name = value;
|
||||||
|
_commandList.Get()->SetName(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public D3D12CommandBuffer(
|
public D3D12CommandBuffer(
|
||||||
D3D12RenderDevice device,
|
D3D12RenderDevice device,
|
||||||
D3D12PipelineLibrary stateController,
|
D3D12PipelineLibrary stateController,
|
||||||
@@ -45,11 +55,18 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
D3D12DescriptorAllocator descriptorAllocator,
|
D3D12DescriptorAllocator descriptorAllocator,
|
||||||
CommandBufferType type)
|
CommandBufferType type)
|
||||||
{
|
{
|
||||||
|
_name = string.Empty;
|
||||||
_type = type;
|
_type = type;
|
||||||
|
|
||||||
|
ID3D12CommandAllocator* pAllocator = default;
|
||||||
|
ID3D12GraphicsCommandList10* pCommandList = default;
|
||||||
var commandListType = ConvertCommandBufferType(type);
|
var commandListType = ConvertCommandBufferType(type);
|
||||||
|
|
||||||
device.NativeDevice->CreateCommandAllocator(commandListType, __uuidof<ID3D12CommandAllocator>(), _allocator.GetVoidAddressOf());
|
device.NativeDevice->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator);
|
||||||
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof<ID3D12GraphicsCommandList10>(), _commandList.GetVoidAddressOf());
|
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
|
||||||
|
|
||||||
|
_allocator.Attach(pAllocator);
|
||||||
|
_commandList.Attach(pCommandList);
|
||||||
|
|
||||||
_pipelineLibrary = stateController;
|
_pipelineLibrary = stateController;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
@@ -89,6 +106,20 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
|
|
||||||
public void Begin()
|
public void Begin()
|
||||||
{
|
{
|
||||||
|
void ResetCommandList()
|
||||||
|
{
|
||||||
|
ThrowIfFailed(_allocator.Get()->Reset());
|
||||||
|
ThrowIfFailed(_commandList.Get()->Reset(_allocator.Get(), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBindlessHeap()
|
||||||
|
{
|
||||||
|
var heaps = stackalloc ID3D12DescriptorHeap*[2];
|
||||||
|
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
|
||||||
|
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
|
||||||
|
_commandList.Get()->SetDescriptorHeaps(2, heaps);
|
||||||
|
}
|
||||||
|
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
if (_isRecording)
|
if (_isRecording)
|
||||||
@@ -96,8 +127,9 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
throw new InvalidOperationException("Command buffer is already recording");
|
throw new InvalidOperationException("Command buffer is already recording");
|
||||||
}
|
}
|
||||||
|
|
||||||
_allocator.Get()->Reset();
|
ResetCommandList();
|
||||||
_commandList.Get()->Reset(_allocator.Get(), null);
|
SetBindlessHeap();
|
||||||
|
|
||||||
_commandCount = 0;
|
_commandCount = 0;
|
||||||
_isRecording = true;
|
_isRecording = true;
|
||||||
}
|
}
|
||||||
@@ -111,58 +143,6 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
|
||||||
{
|
|
||||||
ThrowIfDisposed();
|
|
||||||
ThrowIfNotRecording();
|
|
||||||
IncrementCommandCount();
|
|
||||||
|
|
||||||
var rtvHandles = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[renderTargets.Length];
|
|
||||||
for (var i = 0; i < renderTargets.Length; i++)
|
|
||||||
{
|
|
||||||
var handle = renderTargets[i];
|
|
||||||
if (!handle.IsValid)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
var descriptor = _resourceDatabase.GetResourceInfo(handle.AsResource()).viewGroup;
|
|
||||||
rtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
|
|
||||||
if (dsvHandle != null)
|
|
||||||
{
|
|
||||||
*dsvHandle = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv);
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, rtvHandles, FALSE, dsvHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BeginRenderPass(Handle<Texture> renderTarget, Handle<Texture> depthTarget, Color128 clearColor)
|
|
||||||
{
|
|
||||||
// TODO: Implement render pass begin
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndRenderPass()
|
|
||||||
{
|
|
||||||
ThrowIfDisposed();
|
|
||||||
ThrowIfNotRecording();
|
|
||||||
IncrementCommandCount();
|
|
||||||
|
|
||||||
_commandList.Get()->EndRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetViewport(ViewportDesc viewport)
|
|
||||||
{
|
|
||||||
ThrowIfDisposed();
|
|
||||||
ThrowIfNotRecording();
|
|
||||||
IncrementCommandCount();
|
|
||||||
|
|
||||||
var d3d12Viewport = new D3D12_VIEWPORT(viewport.width, viewport.height, viewport.x, viewport.y, viewport.minDepth, viewport.maxDepth);
|
|
||||||
_commandList.Get()->RSSetViewports(1, &d3d12Viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetScissorRect(RectDesc rect)
|
public void SetScissorRect(RectDesc rect)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
@@ -186,16 +166,141 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->ResourceBarrier(1, &barrier);
|
_commandList.Get()->ResourceBarrier(1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRootSignature(IRootSignature rootSignature)
|
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
||||||
{
|
{
|
||||||
// TODO: Implement root signature setting
|
ThrowIfDisposed();
|
||||||
throw new NotImplementedException();
|
ThrowIfNotRecording();
|
||||||
|
IncrementCommandCount();
|
||||||
|
|
||||||
|
var pRtvHandles = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[renderTargets.Length];
|
||||||
|
for (var i = 0; i < renderTargets.Length; i++)
|
||||||
|
{
|
||||||
|
var handle = renderTargets[i];
|
||||||
|
if (!handle.IsValid)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptor = _resourceDatabase.GetResourceInfo(handle.AsResource()).viewGroup;
|
||||||
|
pRtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pDsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
|
||||||
|
if (pDsvHandle != null)
|
||||||
|
{
|
||||||
|
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPipelineState(IShaderPipeline pipelineState)
|
public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false)
|
||||||
{
|
{
|
||||||
// TODO: Implement pipeline state setting
|
// TODO: Implement render pass begin
|
||||||
throw new NotImplementedException();
|
|
||||||
|
var pRtvDescs = stackalloc D3D12_RENDER_PASS_RENDER_TARGET_DESC[rtDescs.Length];
|
||||||
|
for (var i = 0; i < rtDescs.Length; i++)
|
||||||
|
{
|
||||||
|
var rtDesc = rtDescs[i];
|
||||||
|
if (!rtDesc.texture.IsValid)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceInfo = _resourceDatabase.GetResourceInfo(rtDesc.texture.AsResource());
|
||||||
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv);
|
||||||
|
|
||||||
|
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
|
||||||
|
{
|
||||||
|
cpuDescriptor = cpuHandle,
|
||||||
|
BeginningAccess = new D3D12_RENDER_PASS_BEGINNING_ACCESS
|
||||||
|
{
|
||||||
|
Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
|
||||||
|
Clear = new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
|
||||||
|
{
|
||||||
|
ClearValue = new D3D12_CLEAR_VALUE
|
||||||
|
{
|
||||||
|
Format = resourceInfo.desc.textureDescription.Format.ToDXGIFormat(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.BeginningAccess.Clear.ClearValue.Color[0] = rtDesc.clearColor.r;
|
||||||
|
desc.BeginningAccess.Clear.ClearValue.Color[1] = rtDesc.clearColor.g;
|
||||||
|
desc.BeginningAccess.Clear.ClearValue.Color[2] = rtDesc.clearColor.b;
|
||||||
|
desc.BeginningAccess.Clear.ClearValue.Color[3] = rtDesc.clearColor.a;
|
||||||
|
|
||||||
|
pRtvDescs[i] = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.texture.IsValid ? 1 : 0];
|
||||||
|
if (pDsvDesc != null)
|
||||||
|
{
|
||||||
|
var resourceInfo = _resourceDatabase.GetResourceInfo(depthDesc.texture.AsResource());
|
||||||
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv);
|
||||||
|
|
||||||
|
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
|
||||||
|
{
|
||||||
|
cpuDescriptor = cpuHandle,
|
||||||
|
DepthBeginningAccess = new D3D12_RENDER_PASS_BEGINNING_ACCESS
|
||||||
|
{
|
||||||
|
Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
|
||||||
|
Clear = new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
|
||||||
|
{
|
||||||
|
ClearValue = new D3D12_CLEAR_VALUE
|
||||||
|
{
|
||||||
|
Format = resourceInfo.desc.textureDescription.Format.ToDXGIFormat(),
|
||||||
|
DepthStencil = new D3D12_DEPTH_STENCIL_VALUE
|
||||||
|
{
|
||||||
|
Depth = depthDesc.clearDepth,
|
||||||
|
Stencil = depthDesc.clearStencil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pDsvDesc[0] = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
_commandList.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
|
||||||
|
allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndRenderPass()
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
ThrowIfNotRecording();
|
||||||
|
IncrementCommandCount();
|
||||||
|
|
||||||
|
_commandList.Get()->EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetViewport(ViewportDesc viewport)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
ThrowIfNotRecording();
|
||||||
|
IncrementCommandCount();
|
||||||
|
|
||||||
|
var d3d12Viewport = new D3D12_VIEWPORT(viewport.width, viewport.height, viewport.x, viewport.y, viewport.minDepth, viewport.maxDepth);
|
||||||
|
_commandList.Get()->RSSetViewports(1, &d3d12Viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPipelineState(GraphicsPipelineKey pipelineKey)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
ThrowIfNotRecording();
|
||||||
|
IncrementCommandCount();
|
||||||
|
|
||||||
|
var shaderPipeline = _pipelineLibrary.LoadGraphicsPSO(pipelineKey).GetValueOrThrow();
|
||||||
|
_commandList.Get()->SetPipelineState(shaderPipeline.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer)
|
||||||
|
{
|
||||||
|
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||||
|
_commandList.Get()->SetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
|
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
|
||||||
@@ -232,6 +337,19 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->IASetIndexBuffer(&ibView);
|
_commandList.Get()->IASetIndexBuffer(&ibView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||||
|
{
|
||||||
|
var d3d12Topology = topology switch
|
||||||
|
{
|
||||||
|
PrimitiveTopology.Point => D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
|
||||||
|
PrimitiveTopology.Line => D3D_PRIMITIVE_TOPOLOGY_LINELIST,
|
||||||
|
PrimitiveTopology.Triangle => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
||||||
|
_ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
|
||||||
|
};
|
||||||
|
|
||||||
|
_commandList.Get()->IASetPrimitiveTopology(d3d12Topology);
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0)
|
public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
@@ -250,55 +368,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
_commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Batch draw calls by material to minimize state changes
|
public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||||
public void DrawMesh(Handle<Mesh> mesh, Handle<Material> material)
|
|
||||||
{
|
|
||||||
ThrowIfDisposed();
|
|
||||||
ThrowIfNotRecording();
|
|
||||||
IncrementCommandCount();
|
|
||||||
|
|
||||||
ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh);
|
|
||||||
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material);
|
|
||||||
ref var shaderRef = ref _resourceDatabase.GetShaderReference(materialRef.Shader);
|
|
||||||
|
|
||||||
var shaderPipeline = _pipelineLibrary.GetShaderPipeline(materialRef.Shader);
|
|
||||||
if (shaderPipeline is not D3D12ShaderPipeline d3d12Pipeline)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Shader pipeline is not compiled or invalid");
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandList.Get()->SetPipelineState(d3d12Pipeline.pipelineState.Get());
|
|
||||||
_commandList.Get()->SetGraphicsRootSignature(_pipelineLibrary.DefaultRootSignature);
|
|
||||||
|
|
||||||
// Set viewGroup heaps - CRUCIAL: Use the specialized bindless heap for SM 6.6
|
|
||||||
var heaps = stackalloc ID3D12DescriptorHeap*[2];
|
|
||||||
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
|
|
||||||
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
|
|
||||||
_commandList.Get()->SetDescriptorHeaps(2, heaps);
|
|
||||||
|
|
||||||
var rootParamIndex = 0u;
|
|
||||||
foreach (var cbufferInfo in shaderRef.PerMaterialBufferInfo)
|
|
||||||
{
|
|
||||||
ref var cache = ref materialRef._materialPropertiesCache[(int)cbufferInfo.RegisterSlot];
|
|
||||||
var resource = _resourceDatabase.GetResource(cache.GpuResource.AsResource());
|
|
||||||
_commandList.Get()->SetGraphicsRootConstantBufferView(rootParamIndex++, resource->GetGPUVirtualAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
|
|
||||||
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
|
||||||
|
|
||||||
// For fully bindless rendering, we don't use the Input Assembler stage
|
|
||||||
// Instead, we use instanced drawing where each "instance" represents a triangle
|
|
||||||
// The shader will use SV_InstanceID to index into the index buffer and then into the vertex buffer
|
|
||||||
_commandList.Get()->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
||||||
|
|
||||||
// Draw without vertex/index buffers - use instanced drawing
|
|
||||||
// Each instance represents a triangle (3 vertices)
|
|
||||||
var triangleCount = (uint)meshRef.indices.Count / 3;
|
|
||||||
_commandList.Get()->DrawInstanced(3, triangleCount, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispatch(uint threadGroupCountX, uint threadGroupCountY = 1, uint threadGroupCountZ = 1)
|
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
@@ -307,6 +377,26 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
_commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
ThrowIfNotRecording();
|
||||||
|
IncrementCommandCount();
|
||||||
|
|
||||||
|
_commandList.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DispatchRay()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
// ThrowIfDisposed();
|
||||||
|
// ThrowIfNotRecording();
|
||||||
|
// IncrementCommandCount();
|
||||||
|
|
||||||
|
// _commandList.Get()->DispatchRays();
|
||||||
|
}
|
||||||
|
|
||||||
public void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
public void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
@@ -323,7 +413,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
pUploadResource->Map(0, null, &pMappedData);
|
pUploadResource->Map(0, null, &pMappedData);
|
||||||
fixed (T* pData = data)
|
fixed (T* pData = data)
|
||||||
{
|
{
|
||||||
MemoryUtilities.MemCpy(pMappedData, pData, sizeInBytes);
|
MemoryUtility.MemCpy(pMappedData, pData, sizeInBytes);
|
||||||
}
|
}
|
||||||
pUploadResource->Unmap(0, null);
|
pUploadResource->Unmap(0, null);
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ internal unsafe class D3D12CommandQueue : ICommandQueue
|
|||||||
Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE,
|
Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
fixed (void* queuePtr = &_queue)
|
ID3D12CommandQueue* pQueue = default;
|
||||||
{
|
ID3D12Fence1* pFence = default;
|
||||||
pDevice->CreateCommandQueue(&queueDesc, __uuidof<ID3D12CommandQueue>(), (void**)queuePtr);
|
ThrowIfFailed(pDevice->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue));
|
||||||
}
|
ThrowIfFailed(pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence));
|
||||||
|
|
||||||
pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof<ID3D12Fence1>(), _fence.GetVoidAddressOf());
|
_queue.Attach(pQueue);
|
||||||
|
_fence.Attach(pFence);
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D12CommandQueue()
|
~D3D12CommandQueue()
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Ghost.Core.Utilities;
|
using TerraFX.Interop.DirectX;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
|
||||||
using TerraFX.Interop.DirectX;
|
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
@@ -15,20 +13,27 @@ internal unsafe class D3D12DebugLayer
|
|||||||
|
|
||||||
public D3D12DebugLayer()
|
public D3D12DebugLayer()
|
||||||
{
|
{
|
||||||
D3D12GetDebugInterface(__uuidof<ID3D12Debug6>(), _d3d12Debug.GetVoidAddressOf());
|
ID3D12Debug6* pDebug = default;
|
||||||
_d3d12Debug.Get()->EnableDebugLayer();
|
ThrowIfFailed(D3D12GetDebugInterface(__uuidof(pDebug), (void**)&pDebug));
|
||||||
|
pDebug->EnableDebugLayer();
|
||||||
|
|
||||||
DXGIGetDebugInterface1(0u, __uuidof<IDXGIDebug1>(), _dxgiDebug.GetVoidAddressOf());
|
IDXGIDebug1* pDxgiDebug = default;
|
||||||
_dxgiDebug.Get()->EnableLeakTrackingForThread();
|
ThrowIfFailed(DXGIGetDebugInterface1(0u, __uuidof(pDxgiDebug), (void**)&pDxgiDebug));
|
||||||
|
pDxgiDebug->EnableLeakTrackingForThread();
|
||||||
|
|
||||||
DXGIGetDebugInterface1(0u, __uuidof<IDXGIInfoQueue>(), _dxgiInfoQueue.GetVoidAddressOf());
|
IDXGIInfoQueue* pDxgiInfoQueue = default;
|
||||||
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
|
ThrowIfFailed(DXGIGetDebugInterface1(0u, __uuidof(pDxgiInfoQueue), (void**)&pDxgiInfoQueue));
|
||||||
_dxgiInfoQueue.Get()->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
|
ThrowIfFailed(pDxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true));
|
||||||
|
ThrowIfFailed(pDxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true));
|
||||||
|
|
||||||
|
_d3d12Debug.Attach(pDebug);
|
||||||
|
_dxgiDebug.Attach(pDxgiDebug);
|
||||||
|
_dxgiInfoQueue.Attach(pDxgiInfoQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_dxgiDebug.Get()->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL | DXGI_DEBUG_RLO_IGNORE_INTERNAL);
|
ThrowIfFailed(_dxgiDebug.Get()->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL | DXGI_DEBUG_RLO_IGNORE_INTERNAL));
|
||||||
|
|
||||||
_d3d12Debug.Dispose();
|
_d3d12Debug.Dispose();
|
||||||
_dxgiDebug.Dispose();
|
_dxgiDebug.Dispose();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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;
|
||||||
@@ -35,10 +36,12 @@ internal struct D3D12PipelineState : IDisposable
|
|||||||
// NOTE: This is just a temporary cache for compiled shader code. We will implement a proper disk cache later.
|
// NOTE: This is just a temporary cache for compiled shader code. We will implement a proper disk cache later.
|
||||||
public D3D12GraphicsCompiledResult compileResult;
|
public D3D12GraphicsCompiledResult compileResult;
|
||||||
public D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
public D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
||||||
|
public ComPtr<ID3D12PipelineState> pso;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
compileResult.Dispose();
|
compileResult.Dispose();
|
||||||
|
pso.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,31 +65,16 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
|
|
||||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||||
|
|
||||||
public D3D12PipelineLibrary(D3D12RenderDevice device, D3D12ResourceDatabase resourceDatabase, string? cachePath)
|
public D3D12PipelineLibrary(D3D12RenderDevice device, D3D12ResourceDatabase resourceDatabase)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
_pipelineCache = new();
|
_pipelineCache = new();
|
||||||
|
|
||||||
InitializeLibrary(cachePath);
|
|
||||||
CreateDefaultRootSignature();
|
CreateDefaultRootSignature();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeLibrary(string? filePath)
|
|
||||||
{
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
_device.NativeDevice->CreatePipelineLibrary(null, 0, __uuidof<ID3D12PipelineLibrary1>(), _library.GetVoidAddressOf()).ThrowIfFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileBytes = File.ReadAllBytes(filePath!);
|
|
||||||
fixed (byte* pFileBytes = fileBytes)
|
|
||||||
{
|
|
||||||
_device.NativeDevice->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof<ID3D12PipelineLibrary1>(), _library.GetVoidAddressOf()).ThrowIfFailed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateDefaultRootSignature()
|
private void CreateDefaultRootSignature()
|
||||||
{
|
{
|
||||||
_defaultRootSignature = default;
|
_defaultRootSignature = default;
|
||||||
@@ -97,28 +85,28 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
{
|
{
|
||||||
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
||||||
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
||||||
Descriptor = new D3D12_ROOT_DESCRIPTOR1(0, 0), // b0
|
Descriptor = new D3D12_ROOT_DESCRIPTOR1(RootSignatureLayout.GLOBAL_BUFFER_SLOT, 0), // b0
|
||||||
};
|
};
|
||||||
|
|
||||||
rootParameters[1] = new D3D12_ROOT_PARAMETER1
|
rootParameters[1] = new D3D12_ROOT_PARAMETER1
|
||||||
{
|
{
|
||||||
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
||||||
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
||||||
Descriptor = new D3D12_ROOT_DESCRIPTOR1(1, 0), // b1
|
Descriptor = new D3D12_ROOT_DESCRIPTOR1(RootSignatureLayout.PER_VIEW_BUFFER_SLOT, 0), // b1
|
||||||
};
|
};
|
||||||
|
|
||||||
rootParameters[2] = new D3D12_ROOT_PARAMETER1
|
rootParameters[2] = new D3D12_ROOT_PARAMETER1
|
||||||
{
|
{
|
||||||
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
||||||
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
||||||
Descriptor = new D3D12_ROOT_DESCRIPTOR1(2, 0), // b2
|
Descriptor = new D3D12_ROOT_DESCRIPTOR1(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, 0), // b2
|
||||||
};
|
};
|
||||||
|
|
||||||
rootParameters[3] = new D3D12_ROOT_PARAMETER1
|
rootParameters[3] = new D3D12_ROOT_PARAMETER1
|
||||||
{
|
{
|
||||||
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV,
|
||||||
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
||||||
Descriptor = new D3D12_ROOT_DESCRIPTOR1(3, 0), // b3
|
Descriptor = new D3D12_ROOT_DESCRIPTOR1(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, 0), // b3
|
||||||
};
|
};
|
||||||
|
|
||||||
#if USE_TRADITIONAL_BINDLESS
|
#if USE_TRADITIONAL_BINDLESS
|
||||||
@@ -166,7 +154,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var versionedDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC
|
var versionedDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC
|
||||||
{
|
{
|
||||||
Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
|
Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
|
||||||
@@ -183,8 +170,48 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
throw new InvalidOperationException($"Failed to serialize default root signature: {errorMsg}");
|
throw new InvalidOperationException($"Failed to serialize default root signature: {errorMsg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ID3D12RootSignature* pRootSignature = default;
|
||||||
ThrowIfFailed(_device.NativeDevice->CreateRootSignature(0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(),
|
ThrowIfFailed(_device.NativeDevice->CreateRootSignature(0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(),
|
||||||
__uuidof<ID3D12RootSignature>(), _defaultRootSignature.GetVoidAddressOf()));
|
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||||
|
|
||||||
|
_defaultRootSignature.Attach(pRootSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadLibraryFromDisk(string? filePath)
|
||||||
|
{
|
||||||
|
ID3D12PipelineLibrary1* pLibrary = default;
|
||||||
|
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
{
|
||||||
|
var fileBytes = File.ReadAllBytes(filePath!);
|
||||||
|
fixed (byte* pFileBytes = fileBytes)
|
||||||
|
{
|
||||||
|
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary));
|
||||||
|
}
|
||||||
|
|
||||||
|
_library.Attach(pLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveLibraryToDisk(string filePath)
|
||||||
|
{
|
||||||
|
var dir = Path.GetDirectoryName(filePath);
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Directory does not exist: {dir}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var size = _library.Get()->GetSerializedSize();
|
||||||
|
using var buffer = new UnsafeArray<byte>((int)size, Allocator.Persistent); // We use persistent heap allocation instead of stack allocation to avoid stack overflow for large pipeline libraries.
|
||||||
|
|
||||||
|
ThrowIfFailed(_library.Get()->Serialize(buffer.GetUnsafePtr(), size));
|
||||||
|
|
||||||
|
using var fs = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||||
|
fs.Write(buffer.AsSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateReflectionData(ShaderReflectionData reflectionData)
|
private static void ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||||
@@ -206,19 +233,30 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
{
|
{
|
||||||
static CompileResult CompileAndValidate(ref CompilerConfig config)
|
static CompileResult CompileAndValidate(ref CompilerConfig config)
|
||||||
{
|
{
|
||||||
var reflectionBlob = default(IDxcBlob*);
|
IDxcBlob* reflectionBlob = default;
|
||||||
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow();
|
|
||||||
|
|
||||||
if (reflectionBlob != null)
|
try
|
||||||
{
|
{
|
||||||
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
|
var result = D3D12ShaderCompiler.Compile(ref config, Allocator.Persistent, &reflectionBlob).GetValueOrThrow();
|
||||||
ValidateReflectionData(reflection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
if (reflectionBlob != null)
|
||||||
|
{
|
||||||
|
var reflection = D3D12ShaderCompiler.PerformDXCReflection(reflectionBlob).GetValueOrThrow();
|
||||||
|
ValidateReflectionData(reflection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (reflectionBlob != null)
|
||||||
|
{
|
||||||
|
reflectionBlob->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tsResult = default(CompileResult);
|
CompileResult tsResult = default;
|
||||||
var tsEntry = descriptor.taskShader;
|
var tsEntry = descriptor.taskShader;
|
||||||
if (tsEntry.IsCreated)
|
if (tsEntry.IsCreated)
|
||||||
{
|
{
|
||||||
@@ -304,17 +342,17 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
_ => D3D12_COMPARISON_FUNC_LESS_EQUAL
|
_ => D3D12_COMPARISON_FUNC_LESS_EQUAL
|
||||||
};
|
};
|
||||||
|
|
||||||
private static D3D12_DEPTH_STENCIL_DESC BuildDepthStencil(ref readonly PipelineDescriptor pipeline)
|
private static D3D12_DEPTH_STENCIL_DESC BuildDepthStencil(ZTestOptions ztest, ZWriteOptions zwrite)
|
||||||
{
|
{
|
||||||
var depthEnabled = pipeline.zTest != ZTestOptions.Disabled;
|
var depthEnabled = ztest != ZTestOptions.Disabled;
|
||||||
var writeEnabled = pipeline.zWrite == ZWriteOptions.On;
|
var writeEnabled = zwrite == ZWriteOptions.On;
|
||||||
var cmp = ToD3DCompare(pipeline.zTest);
|
var cmp = ToD3DCompare(ztest);
|
||||||
return D3D12_DEPTH_STENCIL_DESC.Create(depthEnabled, writeEnabled, cmp);
|
return D3D12_DEPTH_STENCIL_DESC.Create(depthEnabled, writeEnabled, cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StorePassState(ShaderPassKey id, ref readonly D3D12GraphicsCompiledResult compiled, ref readonly PipelineDescriptor pipelineDescriptor, ReadOnlySpan<TextureFormat> rtvs, TextureFormat dsv)
|
private GraphicsPipelineKey CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly D3D12GraphicsCompiledResult compiled)
|
||||||
{
|
{
|
||||||
var rtvCount = (uint)Math.Min(rtvs.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
|
var rtvCount = (uint)Math.Min(descriptor.rtvFormats.Length, D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);
|
||||||
|
|
||||||
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
||||||
{
|
{
|
||||||
@@ -325,12 +363,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
SampleMask = UINT32_MAX,
|
SampleMask = UINT32_MAX,
|
||||||
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
|
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
|
||||||
NumRenderTargets = rtvCount,
|
NumRenderTargets = rtvCount,
|
||||||
DSVFormat = dsv.ToDXGIFormat(),
|
DSVFormat = descriptor.dsvFormat.ToDXGIFormat(),
|
||||||
DepthStencilState = BuildDepthStencil(in pipelineDescriptor),
|
DepthStencilState = BuildDepthStencil(descriptor.zTest, descriptor.zWrite),
|
||||||
NodeMask = 0,
|
NodeMask = 0,
|
||||||
Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
|
Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
|
||||||
|
|
||||||
BlendState = pipelineDescriptor.blend switch
|
BlendState = descriptor.blend switch
|
||||||
{
|
{
|
||||||
BlendOptions.Opaque => D3D12_BLEND_DESC.OPAQUE,
|
BlendOptions.Opaque => D3D12_BLEND_DESC.OPAQUE,
|
||||||
BlendOptions.Alpha => D3D12_BLEND_DESC.ALPHA_BLEND,
|
BlendOptions.Alpha => D3D12_BLEND_DESC.ALPHA_BLEND,
|
||||||
@@ -339,7 +377,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
BlendOptions.PremultipliedAlpha => D3D12_BLEND_DESC.PREMULTIPLIED,
|
BlendOptions.PremultipliedAlpha => D3D12_BLEND_DESC.PREMULTIPLIED,
|
||||||
_ => D3D12_BLEND_DESC.OPAQUE
|
_ => D3D12_BLEND_DESC.OPAQUE
|
||||||
},
|
},
|
||||||
RasterizerState = pipelineDescriptor.cull switch
|
RasterizerState = descriptor.cull switch
|
||||||
{
|
{
|
||||||
CullOptions.Off => D3D12_RASTERIZER_DESC.CULL_NONE,
|
CullOptions.Off => D3D12_RASTERIZER_DESC.CULL_NONE,
|
||||||
CullOptions.Front => D3D12_RASTERIZER_DESC.CULL_CLOCKWISE,
|
CullOptions.Front => D3D12_RASTERIZER_DESC.CULL_CLOCKWISE,
|
||||||
@@ -355,36 +393,76 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
|
|
||||||
var hash = new GraphicsPipelineHash
|
var hash = new GraphicsPipelineHash
|
||||||
{
|
{
|
||||||
id = id,
|
id = descriptor.passId,
|
||||||
rtvCount = rtvCount,
|
rtvCount = (uint)descriptor.rtvFormats.Length,
|
||||||
dsvFormat = dsv,
|
dsvFormat = descriptor.dsvFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < rtvCount && i < 6; i++)
|
for (var i = 0; i < rtvCount && i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
|
||||||
{
|
{
|
||||||
desc.RTVFormats[i] = rtvs[i].ToDXGIFormat();
|
desc.RTVFormats[i] = descriptor.rtvFormats[i].ToDXGIFormat();
|
||||||
desc.BlendState.RenderTarget[i].RenderTargetWriteMask = (byte)(pipelineDescriptor.colorMask & 0x0F);
|
desc.BlendState.RenderTarget[i].RenderTargetWriteMask = (byte)(descriptor.colorMask & 0x0F);
|
||||||
hash.rtvFormats[i] = rtvs[i];
|
hash.rtvFormats[i] = descriptor.rtvFormats[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = hash.GetKey();
|
var key = hash.GetKey();
|
||||||
ref var existing = ref CollectionsMarshal.GetValueRefOrAddDefault(_pipelineCache, hash.GetKey(), out var exists);
|
ref var existing = ref CollectionsMarshal.GetValueRefOrAddDefault(_pipelineCache, key, out var exists);
|
||||||
if (exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Pass code cache already contains an entry for key: {key}");
|
existing.compileResult = compiled;
|
||||||
|
existing.psoDesc = desc;
|
||||||
|
|
||||||
|
var streamDesc = new D3D12_PIPELINE_STATE_STREAM_DESC
|
||||||
|
{
|
||||||
|
pPipelineStateSubobjectStream = &desc,
|
||||||
|
SizeInBytes = (nuint)sizeof(D3DX12_MESH_SHADER_PIPELINE_STATE_DESC)
|
||||||
|
};
|
||||||
|
|
||||||
|
ID3D12PipelineState* pPipelineState = default;
|
||||||
|
|
||||||
|
char* pKeyStr = stackalloc char[GraphicsPipelineKey.KEY_STRING_LENGTH];
|
||||||
|
var keySpan = new Span<char>(pKeyStr, GraphicsPipelineKey.KEY_STRING_LENGTH);
|
||||||
|
key.GetString(keySpan).ThrowIfFailed();
|
||||||
|
|
||||||
|
var hr = _library.Get()->LoadPipeline(pKeyStr, &streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState);
|
||||||
|
if (hr == E.E_INVALIDARG)
|
||||||
|
{
|
||||||
|
// Pipeline not found in the library, create a new one.
|
||||||
|
ThrowIfFailed(_device.NativeDevice->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||||
|
ThrowIfFailed(_library.Get()->StorePipeline(pKeyStr, pPipelineState));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.pso.Attach(pPipelineState);
|
||||||
}
|
}
|
||||||
|
|
||||||
existing.compileResult = compiled;
|
return key;
|
||||||
existing.psoDesc = desc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CompilePass(IPassDescriptor descriptor)
|
public GraphicsPipelineKey CompilePassPSO(IPassDescriptor descriptor, ReadOnlySpan<TextureFormat> rtvs, TextureFormat dsv)
|
||||||
{
|
{
|
||||||
|
var key = default(GraphicsPipelineKey);
|
||||||
switch (descriptor)
|
switch (descriptor)
|
||||||
{
|
{
|
||||||
case FullPassDescriptor fullPass:
|
case FullPassDescriptor fullPass:
|
||||||
var result = CompileAndValidateFullPass(fullPass).GetValueOrThrow();
|
var result = CompileAndValidateFullPass(fullPass).GetValueOrThrow();
|
||||||
StorePassState(new(fullPass.Identifier), in result, in fullPass.localPipeline, [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown);
|
var psoDes = new GraphicsPSODescriptor
|
||||||
|
{
|
||||||
|
passId = new(fullPass.Identifier),
|
||||||
|
zTest = fullPass.localPipeline.zTest,
|
||||||
|
zWrite = fullPass.localPipeline.zWrite,
|
||||||
|
cull = fullPass.localPipeline.cull,
|
||||||
|
blend = fullPass.localPipeline.blend,
|
||||||
|
colorMask = fullPass.localPipeline.colorMask,
|
||||||
|
|
||||||
|
rtvFormats = rtvs,
|
||||||
|
dsvFormat = dsv,
|
||||||
|
};
|
||||||
|
|
||||||
|
key = CompilePSO(in psoDes, in result);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Do we need to support other pass types?
|
// Do we need to support other pass types?
|
||||||
@@ -392,82 +470,31 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CompileShader(ShaderDescriptor descriptor)
|
public Result<Ptr<ID3D12PipelineState>> LoadGraphicsPSO(GraphicsPipelineKey key)
|
||||||
{
|
{
|
||||||
foreach (var pass in descriptor.passes)
|
ref var cacheEntry = ref CollectionsMarshal.GetValueRefOrNullRef(_pipelineCache, key);
|
||||||
|
if (Unsafe.IsNullRef(ref cacheEntry))
|
||||||
{
|
{
|
||||||
CompilePass(pass);
|
return Result.Fail("Pipeline state not found in cache.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Pipeline variants (keywords)
|
return new Ptr<ID3D12PipelineState>(cacheEntry.pso.Get());
|
||||||
// TODO: Disk caching
|
|
||||||
// TODO: Async compilation
|
|
||||||
public void PreCookPipelineState()
|
|
||||||
{
|
|
||||||
foreach (var kvp in _pipelineCache)
|
|
||||||
{
|
|
||||||
var key = kvp.Key;
|
|
||||||
var state = kvp.Value;
|
|
||||||
|
|
||||||
var streamDesc = new D3D12_PIPELINE_STATE_STREAM_DESC
|
|
||||||
{
|
|
||||||
pPipelineStateSubobjectStream = &state.psoDesc,
|
|
||||||
SizeInBytes = (nuint)sizeof(D3DX12_MESH_SHADER_PIPELINE_STATE_DESC)
|
|
||||||
};
|
|
||||||
|
|
||||||
ComPtr<ID3D12PipelineState> pipelineState = default;
|
|
||||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineState(&streamDesc, __uuidof<ID3D12PipelineState>(), pipelineState.GetVoidAddressOf()));
|
|
||||||
|
|
||||||
var name = key.ToString();
|
|
||||||
fixed (char* pName = name)
|
|
||||||
{
|
|
||||||
ThrowIfFailed(_library.Get()->StorePipeline(pName, pipelineState.Get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ID3D12PipelineState* LoadPipelineState(GraphicsPipelineKey key)
|
|
||||||
{
|
|
||||||
var name = key.ToString();
|
|
||||||
var state = _pipelineCache[key];
|
|
||||||
var streamDesc = new D3D12_PIPELINE_STATE_STREAM_DESC
|
|
||||||
{
|
|
||||||
pPipelineStateSubobjectStream = &state.psoDesc,
|
|
||||||
SizeInBytes = (nuint)sizeof(D3DX12_MESH_SHADER_PIPELINE_STATE_DESC)
|
|
||||||
};
|
|
||||||
|
|
||||||
fixed (char* pName = name)
|
|
||||||
{
|
|
||||||
ID3D12PipelineState* pipelineState;
|
|
||||||
ThrowIfFailed(_library.Get()->LoadPipeline(pName, &streamDesc, __uuidof<ID3D12PipelineState>(), (void**)&pipelineState));
|
|
||||||
|
|
||||||
return pipelineState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveLibraryToDisk(string filePath)
|
|
||||||
{
|
|
||||||
var size = _library.Get()->GetSerializedSize();
|
|
||||||
using var buffer = new UnsafeArray<byte>((int)size, Allocator.Persistent); // We use persistent heap allocation instead of stack allocation to avoid stack overflow for large pipeline libraries.
|
|
||||||
|
|
||||||
ThrowIfFailed(_library.Get()->Serialize(buffer.GetUnsafePtr(), size));
|
|
||||||
|
|
||||||
var fs = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
||||||
fs.Write(buffer.AsSpan());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_defaultRootSignature.Dispose();
|
|
||||||
|
|
||||||
foreach (var kvp in _pipelineCache)
|
foreach (var kvp in _pipelineCache)
|
||||||
{
|
{
|
||||||
kvp.Value.Dispose();
|
kvp.Value.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_pipelineCache.Clear();
|
||||||
|
|
||||||
|
_defaultRootSignature.Dispose();
|
||||||
_library.Dispose();
|
_library.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,16 +47,20 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
|||||||
|
|
||||||
private void InitializeDevice()
|
private void InitializeDevice()
|
||||||
{
|
{
|
||||||
|
IDXGIFactory7* pFactory = default;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
CreateDXGIFactory2(TRUE, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
|
CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory);
|
||||||
#else
|
#else
|
||||||
CreateDXGIFactory2(FALSE, __uuidof<IDXGIFactory7>(), _dxgiFactory.GetVoidAddressOf());
|
CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_dxgiFactory.Attach(pFactory);
|
||||||
|
|
||||||
|
ID3D12Device14* pDevice = default;
|
||||||
ComPtr<IDXGIAdapter1> adapter = default;
|
ComPtr<IDXGIAdapter1> adapter = default;
|
||||||
|
|
||||||
for (uint adapterIndex = 0;
|
for (uint adapterIndex = 0;
|
||||||
_dxgiFactory.Get()->EnumAdapterByGpuPreference(adapterIndex, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof<IDXGIAdapter1>(), adapter.ReleaseAndGetVoidAddressOf()).SUCCEEDED;
|
_dxgiFactory.Get()->EnumAdapterByGpuPreference(adapterIndex, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, adapter.IID(), adapter.ReleaseAndGetVoidAddressOf()).SUCCEEDED;
|
||||||
adapterIndex++)
|
adapterIndex++)
|
||||||
{
|
{
|
||||||
DXGI_ADAPTER_DESC1 desc = default;
|
DXGI_ADAPTER_DESC1 desc = default;
|
||||||
@@ -68,18 +72,20 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (D3D12CreateDevice((IUnknown*)adapter.Get(), D3D_FEATURE_LEVEL_12_0, __uuidof<ID3D12Device14>(), _device.GetVoidAddressOf()).SUCCEEDED)
|
if (D3D12CreateDevice((IUnknown*)adapter.Get(), D3D_FEATURE_LEVEL_12_0, __uuidof(pDevice), (void**)&pDevice).SUCCEEDED)
|
||||||
{
|
{
|
||||||
_adapter = adapter.Move();
|
_adapter = adapter.Move();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_device.Get() == null)
|
if (pDevice == null)
|
||||||
{
|
{
|
||||||
adapter.Dispose(); // Dispose the last adapter we tried. If the operation succeeded, we would have moved it.
|
adapter.Dispose(); // Dispose the last adapter we tried. If the operation succeeded, we would have moved it.
|
||||||
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_device.Attach(pDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -11,6 +10,7 @@ using static TerraFX.Aliases.D3D12_Alias;
|
|||||||
using static TerraFX.Aliases.D3D12MA_Alias;
|
using static TerraFX.Aliases.D3D12MA_Alias;
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
using static TerraFX.Interop.DirectX.D3D12MemAlloc;
|
using static TerraFX.Interop.DirectX.D3D12MemAlloc;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
|
|
||||||
private ComPtr<D3D12MA_Allocator> _allocator;
|
private ComPtr<D3D12MA_Allocator> _allocator;
|
||||||
|
|
||||||
private readonly D3D12RenderDevice _device;
|
|
||||||
private readonly RenderSystem _renderSystem;
|
private readonly RenderSystem _renderSystem;
|
||||||
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private D3D12_SHADER_RESOURCE_VIEW_DESC CreateSrvDesc(ID3D12Resource* pResource, bool isCubeMap, uint mipLevels, uint arraySize)
|
private static D3D12_SHADER_RESOURCE_VIEW_DESC CreateSrvDesc(ID3D12Resource* pResource, bool isCubeMap, uint mipLevels, uint arraySize)
|
||||||
{
|
{
|
||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = pResource->GetDesc();
|
||||||
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
|
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
|
||||||
@@ -93,17 +93,6 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
|
|
||||||
switch (resourceDesc.Dimension)
|
switch (resourceDesc.Dimension)
|
||||||
{
|
{
|
||||||
case D3D12_RESOURCE_DIMENSION_BUFFER:
|
|
||||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
|
||||||
srvDesc.Buffer = new D3D12_BUFFER_SRV
|
|
||||||
{
|
|
||||||
FirstElement = 0,
|
|
||||||
NumElements = (uint)(resourceDesc.Width / 4),
|
|
||||||
StructureByteStride = 0,
|
|
||||||
Flags = D3D12_BUFFER_SRV_FLAG_RAW,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
||||||
if (resourceDesc.DepthOrArraySize > 1)
|
if (resourceDesc.DepthOrArraySize > 1)
|
||||||
{
|
{
|
||||||
@@ -180,7 +169,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
return srvDesc;
|
return srvDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private D3D12_RENDER_TARGET_VIEW_DESC CreateRtvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, uint planeSlice = 0)
|
private static D3D12_RENDER_TARGET_VIEW_DESC CreateRtvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, uint planeSlice = 0)
|
||||||
{
|
{
|
||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = pResource->GetDesc();
|
||||||
var rtvDesc = new D3D12_RENDER_TARGET_VIEW_DESC();
|
var rtvDesc = new D3D12_RENDER_TARGET_VIEW_DESC();
|
||||||
@@ -276,7 +265,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
return rtvDesc;
|
return rtvDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private D3D12_DEPTH_STENCIL_VIEW_DESC CreateDsvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, D3D12_DSV_FLAGS flags = D3D12_DSV_FLAG_NONE)
|
private static D3D12_DEPTH_STENCIL_VIEW_DESC CreateDsvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, D3D12_DSV_FLAGS flags = D3D12_DSV_FLAG_NONE)
|
||||||
{
|
{
|
||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = pResource->GetDesc();
|
||||||
var dsvDesc = new D3D12_DEPTH_STENCIL_VIEW_DESC
|
var dsvDesc = new D3D12_DEPTH_STENCIL_VIEW_DESC
|
||||||
@@ -344,6 +333,88 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
return dsvDesc;
|
return dsvDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static D3D12_UNORDERED_ACCESS_VIEW_DESC CreateUavDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, uint planeSlice = 0)
|
||||||
|
{
|
||||||
|
var resourceDesc = pResource->GetDesc();
|
||||||
|
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
|
||||||
|
{
|
||||||
|
Format = resourceDesc.Format
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (resourceDesc.Dimension)
|
||||||
|
{
|
||||||
|
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
||||||
|
if (resourceDesc.DepthOrArraySize > 1)
|
||||||
|
{
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
|
||||||
|
uavDesc.Texture1DArray = new D3D12_TEX1D_ARRAY_UAV
|
||||||
|
{
|
||||||
|
MipSlice = mipSlice,
|
||||||
|
FirstArraySlice = firstArraySlice,
|
||||||
|
ArraySize = resourceDesc.ArraySize() - firstArraySlice
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D;
|
||||||
|
uavDesc.Texture1D = new D3D12_TEX1D_UAV
|
||||||
|
{
|
||||||
|
MipSlice = mipSlice
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
||||||
|
if (resourceDesc.DepthOrArraySize > 1)
|
||||||
|
{
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
|
||||||
|
uavDesc.Texture2DArray = new D3D12_TEX2D_ARRAY_UAV
|
||||||
|
{
|
||||||
|
MipSlice = mipSlice,
|
||||||
|
FirstArraySlice = firstArraySlice,
|
||||||
|
ArraySize = resourceDesc.ArraySize() - firstArraySlice,
|
||||||
|
PlaneSlice = planeSlice
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||||
|
uavDesc.Texture2D = new D3D12_TEX2D_UAV
|
||||||
|
{
|
||||||
|
MipSlice = mipSlice,
|
||||||
|
PlaneSlice = planeSlice
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
|
||||||
|
uavDesc.Texture3D = new D3D12_TEX3D_UAV
|
||||||
|
{
|
||||||
|
MipSlice = mipSlice,
|
||||||
|
FirstWSlice = firstArraySlice,
|
||||||
|
WSize = resourceDesc.Depth() - firstArraySlice
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case D3D12_RESOURCE_DIMENSION_BUFFER:
|
||||||
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||||
|
uavDesc.Buffer = new D3D12_BUFFER_UAV
|
||||||
|
{
|
||||||
|
FirstElement = 0,
|
||||||
|
NumElements = (uint)(resourceDesc.Width / 4), // Assuming R32_TYPELESS RAW
|
||||||
|
StructureByteStride = 0,
|
||||||
|
Flags = D3D12_BUFFER_UAV_FLAG_RAW
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unsupported texture dimension for UAV: {resourceDesc.Dimension}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return uavDesc;
|
||||||
|
}
|
||||||
|
|
||||||
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
|
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
|
||||||
{
|
{
|
||||||
CheckTexture2DSize(desc.Width, desc.Height);
|
CheckTexture2DSize(desc.Width, desc.Height);
|
||||||
@@ -434,17 +505,10 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
||||||
{
|
{
|
||||||
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||||
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
||||||
{
|
var uavDesc = CreateUavDesc(allocation.Get()->GetResource());
|
||||||
ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D,
|
|
||||||
Format = d3d12Format,
|
_device.NativeDevice->CreateUnorderedAccessView(allocation.Get()->GetResource(), null, &uavDesc, cpuHandle);
|
||||||
Texture2D = new D3D12_TEX2D_UAV
|
|
||||||
{
|
|
||||||
MipSlice = 0,
|
|
||||||
PlaneSlice = 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_device.NativeDevice->CreateUnorderedAccessView(allocation.Get()->GetResource(), null, &uavDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var handle = TrackResource(allocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
|
var handle = TrackResource(allocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
|
||||||
@@ -458,11 +522,14 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
return CreateTexture(ref textureDesc, isTemp);
|
return CreateTexture(ref textureDesc, isTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIX: This is not correct! Fix it!
|
||||||
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
|
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
|
||||||
{
|
{
|
||||||
CheckBufferSize(desc.Size);
|
CheckBufferSize(desc.Size);
|
||||||
|
|
||||||
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
|
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
|
||||||
|
resourceDescription.Format = desc.Usage.HasFlag(BufferUsage.Raw) ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_UNKNOWN;
|
||||||
|
|
||||||
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
||||||
{
|
{
|
||||||
HeapType = ConvertMemoryType(desc.MemoryType),
|
HeapType = ConvertMemoryType(desc.MemoryType),
|
||||||
@@ -473,7 +540,7 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
|
|
||||||
ComPtr<D3D12MA_Allocation> allocation = default;
|
ComPtr<D3D12MA_Allocation> allocation = default;
|
||||||
ThrowIfFailed(_allocator.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, allocation.GetAddressOf(), Win32Utility.IID_NULL, null));
|
ThrowIfFailed(_allocator.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, allocation.GetAddressOf(), Win32Utility.IID_NULL, null));
|
||||||
|
|
||||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||||
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
|
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
|
||||||
{
|
{
|
||||||
@@ -752,4 +819,4 @@ internal unsafe class D3D12ResourceAllocator : IResourceAllocator, IDisposable
|
|||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Collections;
|
using Misaki.HighPerformance.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
@@ -8,6 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
|
|
||||||
var id = _shaders.Count;
|
var id = _shaders.Count;
|
||||||
_shaders.Add(shader);
|
_shaders.Add(shader);
|
||||||
return new Identifier<SDL>(id);
|
return new Identifier<Shader>(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasShader(Identifier<Shader> id)
|
public bool HasShader(Identifier<Shader> id)
|
||||||
@@ -487,4 +487,4 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
|
|
||||||
public static Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator, IDxcBlob** ppReflectionBlob)
|
public static Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator, IDxcBlob** ppReflectionBlob)
|
||||||
{
|
{
|
||||||
|
// NOTE: Should we cache the compiler and utils instances for better performance?
|
||||||
using ComPtr<IDxcCompiler3> compiler = default;
|
using ComPtr<IDxcCompiler3> compiler = default;
|
||||||
using ComPtr<IDxcUtils> utils = default;
|
using ComPtr<IDxcUtils> utils = default;
|
||||||
using ComPtr<IDxcIncludeHandler> includeHandler = default;
|
using ComPtr<IDxcIncludeHandler> includeHandler = default;
|
||||||
@@ -206,8 +207,8 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
var pDxcCompiler = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcCompiler);
|
var pDxcCompiler = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcCompiler);
|
||||||
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
|
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
|
||||||
|
|
||||||
ThrowIfFailed(DxcCreateInstance(pDxcCompiler, __uuidof<IDxcCompiler3>(), compiler.GetVoidAddressOf()));
|
ThrowIfFailed(DxcCreateInstance(pDxcCompiler, compiler.IID(), compiler.PPV()));
|
||||||
ThrowIfFailed(DxcCreateInstance(pDxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf()));
|
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV()));
|
||||||
|
|
||||||
//includeHandler.Get()->LoadSource();
|
//includeHandler.Get()->LoadSource();
|
||||||
utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf());
|
utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf());
|
||||||
@@ -216,7 +217,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
using ComPtr<IDxcBlobEncoding> sourceBlob = default;
|
using ComPtr<IDxcBlobEncoding> sourceBlob = default;
|
||||||
if (utils.Get()->LoadFile(config.shaderPath.AsSpan().GetUnsafePtr(), null, sourceBlob.GetAddressOf()).FAILED)
|
if (utils.Get()->LoadFile(config.shaderPath.AsSpan().GetUnsafePtr(), null, sourceBlob.GetAddressOf()).FAILED)
|
||||||
{
|
{
|
||||||
return Result<CompileResult>.Fail($"Failed to load shader file: {config.shaderPath}");
|
return Result.Fail($"Failed to load shader file: {config.shaderPath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var argsArray = GetCompilerArguments(in config);
|
var argsArray = GetCompilerArguments(in config);
|
||||||
@@ -237,7 +238,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
Encoding = DXC.DXC_CP_UTF8
|
Encoding = DXC.DXC_CP_UTF8
|
||||||
};
|
};
|
||||||
|
|
||||||
ThrowIfFailed(compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler.Get(), __uuidof<IDxcResult>(), result.GetVoidAddressOf()));
|
ThrowIfFailed(compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler.Get(), result.IID(), result.PPV()));
|
||||||
|
|
||||||
// Check compilation result
|
// Check compilation result
|
||||||
HRESULT hrStatus;
|
HRESULT hrStatus;
|
||||||
@@ -251,11 +252,11 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
if (errorBlob.Get() != null)
|
if (errorBlob.Get() != null)
|
||||||
{
|
{
|
||||||
var errorMessage = Marshal.PtrToStringUni((IntPtr)errorBlob.Get()->GetBufferPointer());
|
var errorMessage = Marshal.PtrToStringUni((IntPtr)errorBlob.Get()->GetBufferPointer());
|
||||||
return Result<CompileResult>.Fail($"DXC shader compilation failed:\n{errorMessage}");
|
return Result.Fail($"DXC shader compilation failed:\n{errorMessage}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Result<CompileResult>.Fail("DXC shader compilation failed with unknown error.");
|
return Result.Fail("DXC shader compilation failed with unknown error.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +301,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
// Create DXC utils to parse reflection data
|
// Create DXC utils to parse reflection data
|
||||||
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
|
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
|
||||||
using ComPtr<IDxcUtils> utils = default;
|
using ComPtr<IDxcUtils> utils = default;
|
||||||
ThrowIfFailed(DxcCreateInstance(pDxcUtils, __uuidof<IDxcUtils>(), utils.GetVoidAddressOf()));
|
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV()));
|
||||||
|
|
||||||
// Create reflection interface from blob
|
// Create reflection interface from blob
|
||||||
var reflectionBuffer = new DxcBuffer
|
var reflectionBuffer = new DxcBuffer
|
||||||
@@ -311,7 +312,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
};
|
};
|
||||||
|
|
||||||
using ComPtr<ID3D12ShaderReflection> reflection = default;
|
using ComPtr<ID3D12ShaderReflection> reflection = default;
|
||||||
ThrowIfFailed(utils.Get()->CreateReflection(&reflectionBuffer, __uuidof<ID3D12ShaderReflection>(), reflection.GetVoidAddressOf()));
|
ThrowIfFailed(utils.Get()->CreateReflection(&reflectionBuffer, reflection.IID(), reflection.PPV()));
|
||||||
|
|
||||||
D3D12_SHADER_DESC shaderDesc;
|
D3D12_SHADER_DESC shaderDesc;
|
||||||
ThrowIfFailed(reflection.Get()->GetDesc(&shaderDesc));
|
ThrowIfFailed(reflection.Get()->GetDesc(&shaderDesc));
|
||||||
@@ -326,7 +327,7 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
var resourceName = Marshal.PtrToStringUTF8((IntPtr)bindDesc.Name);
|
var resourceName = Marshal.PtrToStringUTF8((IntPtr)bindDesc.Name);
|
||||||
if (resourceName == null)
|
if (resourceName == null)
|
||||||
{
|
{
|
||||||
return Result<ShaderReflectionData>.Fail("Failed to get resource name from reflection data.");
|
return Result.Fail("Failed to get resource name from reflection data.");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bindDesc.Type)
|
switch (bindDesc.Type)
|
||||||
@@ -391,4 +392,4 @@ internal static unsafe class D3D12ShaderCompiler
|
|||||||
|
|
||||||
return reflectionData;
|
return reflectionData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ghost.Core;
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Contracts;
|
using Ghost.Graphics.Contracts;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
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;
|
||||||
@@ -12,6 +11,8 @@ using TerraFX.Interop.Windows;
|
|||||||
|
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
|
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -105,10 +106,10 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
throw new ArgumentException("Unsupported swap chain target type.");
|
throw new ArgumentException("Unsupported swap chain target type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tempSwapChain.Get()->QueryInterface(__uuidof<IDXGISwapChain4>(), _swapChain.GetVoidAddressOf()).FAILED)
|
IDXGISwapChain4* pSwapChain = default;
|
||||||
{
|
tempSwapChain.Get()->QueryInterface(__uuidof(pSwapChain), (void**)&pSwapChain);
|
||||||
throw new InvalidOperationException("Failed to create IDXGISwapChain4 interface.");
|
|
||||||
}
|
_swapChain.Attach(pSwapChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateBackBuffers()
|
private void CreateBackBuffers()
|
||||||
@@ -116,10 +117,10 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
for (uint i = 0; i < BufferCount; i++)
|
for (uint i = 0; i < BufferCount; i++)
|
||||||
{
|
{
|
||||||
ComPtr<ID3D12Resource> backBuffer = default;
|
ComPtr<ID3D12Resource> backBuffer = default;
|
||||||
_swapChain.Get()->GetBuffer(i, __uuidof<ID3D12Resource>(), backBuffer.GetVoidAddressOf());
|
_swapChain.Get()->GetBuffer(i, backBuffer.IID(), backBuffer.PPV());
|
||||||
backBuffer.Get()->SetName($"SwapChain_BackBuffer_{i}");
|
backBuffer.Get()->SetName($"SwapChain_BackBuffer_{i}");
|
||||||
|
|
||||||
_backBuffers[i] = _resourceDatabase.ImportExternalResource(backBuffer.Move(), ResourceState.Present).AsTexture();
|
_backBuffers[i] = _resourceDatabase.ImportExternalResource(backBuffer, ResourceState.Present).AsTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,4 +183,4 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
_backBuffers.Dispose();
|
_backBuffers.Dispose();
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Ghost.Core.Utilities;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -277,33 +278,33 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
NodeMask = 0
|
NodeMask = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
fixed (void* heapPtr = &_heap)
|
ID3D12DescriptorHeap* pHeap = default;
|
||||||
|
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap);
|
||||||
|
if (hr.FAILED)
|
||||||
{
|
{
|
||||||
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
return false;
|
||||||
if (hr.FAILED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_heap.Attach(pHeap);
|
||||||
|
|
||||||
_startCpuHandle = _heap.Get()->GetCPUDescriptorHandleForHeapStart();
|
_startCpuHandle = _heap.Get()->GetCPUDescriptorHandleForHeapStart();
|
||||||
_allocatedDescriptors.Resize(numDescriptors);
|
_allocatedDescriptors.Resize(numDescriptors);
|
||||||
|
|
||||||
if (ShaderVisible)
|
if (ShaderVisible)
|
||||||
{
|
{
|
||||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
ID3D12DescriptorHeap* pShaderVisibleHeap = default;
|
||||||
|
|
||||||
fixed (void* heapPtr = &_shaderVisibleHeap)
|
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||||
|
hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap);
|
||||||
|
if (hr.FAILED)
|
||||||
{
|
{
|
||||||
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof<ID3D12DescriptorHeap>(), (void**)heapPtr);
|
return false;
|
||||||
if (hr.FAILED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_startCpuHandleShaderVisible = _shaderVisibleHeap.Get()->GetCPUDescriptorHandleForHeapStart();
|
_startCpuHandleShaderVisible = pShaderVisibleHeap->GetCPUDescriptorHandleForHeapStart();
|
||||||
_startGpuHandleShaderVisible = _shaderVisibleHeap.Get()->GetGPUDescriptorHandleForHeapStart();
|
_startGpuHandleShaderVisible = pShaderVisibleHeap->GetGPUDescriptorHandleForHeapStart();
|
||||||
|
|
||||||
|
_shaderVisibleHeap.Attach(pShaderVisibleHeap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Ghost.Graphics.Data;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12.Utilities;
|
namespace Ghost.Graphics.D3D12.Utilities;
|
||||||
|
|
||||||
@@ -9,11 +9,11 @@ internal unsafe static class D3D12PipelineResource
|
|||||||
public const int BACK_BUFFER_COUNT = 2;
|
public const int BACK_BUFFER_COUNT = 2;
|
||||||
|
|
||||||
private readonly static D3D12_INPUT_ELEMENT_DESC[] s_inputElementDescs = [
|
private readonly static D3D12_INPUT_ELEMENT_DESC[] s_inputElementDescs = [
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.position.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Ghost.Graphics.Core.Semantic.position.GetUnsafePointer(), SemanticIndex = 0u, Format = Ghost.Graphics.Core.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.normal.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Ghost.Graphics.Core.Semantic.normal.GetUnsafePointer(), SemanticIndex = 0u, Format = Ghost.Graphics.Core.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.tangent.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Ghost.Graphics.Core.Semantic.tangent.GetUnsafePointer(), SemanticIndex = 0u, Format = Ghost.Graphics.Core.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.uv.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Ghost.Graphics.Core.Semantic.uv.GetUnsafePointer(), SemanticIndex = 0u, Format = Ghost.Graphics.Core.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.color.GetUnsafePointer(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Ghost.Graphics.Core.Semantic.color.GetUnsafePointer(), SemanticIndex = 0u, Format = Ghost.Graphics.Core.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
];
|
];
|
||||||
|
|
||||||
public const DXGI_FORMAT SWAP_CHAIN_BACK_BUFFER_FORMAT = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
public const DXGI_FORMAT SWAP_CHAIN_BACK_BUFFER_FORMAT = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
|||||||
@@ -144,9 +144,13 @@ internal static class D3D12_DEPTH_STENCILOP_DESC_Extensions
|
|||||||
|
|
||||||
internal unsafe static class D3D12Utility
|
internal unsafe static class D3D12Utility
|
||||||
{
|
{
|
||||||
public static void SetName(ref this ID3D12Resource resource, ReadOnlySpan<char> name)
|
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
||||||
|
where T : unmanaged, ID3D12Object.Interface
|
||||||
{
|
{
|
||||||
resource.SetName(name.GetUnsafePtr());
|
fixed (char* pName = name)
|
||||||
|
{
|
||||||
|
obj.SetName(pName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureDimension ToTextureDimension(this D3D12_RESOURCE_DIMENSION dimension)
|
public static TextureDimension ToTextureDimension(this D3D12_RESOURCE_DIMENSION dimension)
|
||||||
@@ -187,4 +191,22 @@ internal unsafe static class D3D12Utility
|
|||||||
_ => TextureFormat.Unknown,
|
_ => TextureFormat.Unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static D3D12_RESOURCE_STATES ToD3D12States(this ResourceState state)
|
||||||
|
{
|
||||||
|
return state switch
|
||||||
|
{
|
||||||
|
ResourceState.Common or ResourceState.Present => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COMMON,
|
||||||
|
ResourceState.VertexAndConstantBuffer => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER,
|
||||||
|
ResourceState.IndexBuffer => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_INDEX_BUFFER,
|
||||||
|
ResourceState.RenderTarget => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||||
|
ResourceState.UnorderedAccess => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
|
ResourceState.DepthWrite => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
||||||
|
ResourceState.DepthRead => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_DEPTH_READ,
|
||||||
|
ResourceState.PixelShaderResource => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||||
|
ResourceState.CopyDest => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
|
||||||
|
ResourceState.CopySource => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||||
|
_ => throw new ArgumentException($"Unknown resource state: {state}")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
namespace Ghost.Graphics.Data;
|
|
||||||
|
|
||||||
public class Camera
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Core;
|
||||||
|
using Ghost.Core.Graphics;
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -35,6 +38,8 @@ public readonly struct ShaderPassKey
|
|||||||
|
|
||||||
public readonly struct GraphicsPipelineKey
|
public readonly struct GraphicsPipelineKey
|
||||||
{
|
{
|
||||||
|
public const int KEY_STRING_LENGTH = 17; // 16 chars + null terminator
|
||||||
|
|
||||||
public readonly ulong value;
|
public readonly ulong value;
|
||||||
|
|
||||||
public GraphicsPipelineKey(ulong value)
|
public GraphicsPipelineKey(ulong value)
|
||||||
@@ -42,6 +47,17 @@ public readonly struct GraphicsPipelineKey
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result GetString(Span<char> destination)
|
||||||
|
{
|
||||||
|
if (!value.TryFormat(destination, out _, "X16"))
|
||||||
|
{
|
||||||
|
return Result.Fail("Failed to format GraphicsPipelineKey to string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
destination[16] = '\0';
|
||||||
|
return Result.Success();
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return value.ToString("X16");
|
return value.ToString("X16");
|
||||||
@@ -55,14 +71,14 @@ public readonly struct GraphicsPipelineKey
|
|||||||
|
|
||||||
internal struct GraphicsPipelineHash
|
internal struct GraphicsPipelineHash
|
||||||
{
|
{
|
||||||
[InlineArray(8)]
|
[InlineArray(D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT)]
|
||||||
public struct rtv_array
|
public struct rtv_array
|
||||||
{
|
{
|
||||||
public TextureFormat rtvFormats;
|
public TextureFormat rtvFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
public rtv_array rtvFormats;
|
|
||||||
public ShaderPassKey id;
|
public ShaderPassKey id;
|
||||||
|
public rtv_array rtvFormats;
|
||||||
public uint rtvCount;
|
public uint rtvCount;
|
||||||
public TextureFormat dsvFormat;
|
public TextureFormat dsvFormat;
|
||||||
// Do we need to store blend state?
|
// Do we need to store blend state?
|
||||||
@@ -70,12 +86,12 @@ internal struct GraphicsPipelineHash
|
|||||||
|
|
||||||
public readonly GraphicsPipelineKey GetKey()
|
public readonly GraphicsPipelineKey GetKey()
|
||||||
{
|
{
|
||||||
Span<ulong> data = stackalloc ulong[3 + 8];
|
Span<ulong> data = stackalloc ulong[3 + D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
|
||||||
data[0] = id.value;
|
data[0] = id.value;
|
||||||
data[1] = rtvCount;
|
data[1] = rtvCount;
|
||||||
data[2] = (ulong)dsvFormat;
|
data[2] = (ulong)dsvFormat;
|
||||||
|
|
||||||
for (var i = 0; i < 8; i++)
|
for (var i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
|
||||||
{
|
{
|
||||||
data[3 + i] = (ulong)rtvFormats[i];
|
data[3 + i] = (ulong)rtvFormats[i];
|
||||||
}
|
}
|
||||||
@@ -85,6 +101,18 @@ internal struct GraphicsPipelineHash
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ref struct GraphicsPSODescriptor
|
||||||
|
{
|
||||||
|
public ShaderPassKey passId;
|
||||||
|
public ZTestOptions zTest;
|
||||||
|
public ZWriteOptions zWrite;
|
||||||
|
public CullOptions cull;
|
||||||
|
public BlendOptions blend;
|
||||||
|
public uint colorMask;
|
||||||
|
|
||||||
|
public ReadOnlySpan<TextureFormat> rtvFormats;
|
||||||
|
public TextureFormat dsvFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public struct ViewportDesc
|
public struct ViewportDesc
|
||||||
@@ -112,6 +140,20 @@ public struct SubResourceData
|
|||||||
public nint slicePitch;
|
public nint slicePitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct PassRenderTargetDesc
|
||||||
|
{
|
||||||
|
public Handle<Texture> texture;
|
||||||
|
public Color128 clearColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct PassDepthStencilDesc
|
||||||
|
{
|
||||||
|
public Handle<Texture> texture;
|
||||||
|
public float clearDepth;
|
||||||
|
public byte clearStencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
public struct ResourceDesc
|
public struct ResourceDesc
|
||||||
{
|
{
|
||||||
@@ -501,9 +543,6 @@ public struct SwapChainTarget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Swap chain target types
|
|
||||||
/// </summary>
|
|
||||||
public enum SwapChainTargetType
|
public enum SwapChainTargetType
|
||||||
{
|
{
|
||||||
WindowHandle,
|
WindowHandle,
|
||||||
@@ -627,6 +666,13 @@ public enum IndexType
|
|||||||
UInt32
|
UInt32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum PrimitiveTopology
|
||||||
|
{
|
||||||
|
Point,
|
||||||
|
Line,
|
||||||
|
Triangle,
|
||||||
|
}
|
||||||
|
|
||||||
// SDL compiler
|
// SDL compiler
|
||||||
|
|
||||||
internal ref struct CompilerConfig
|
internal ref struct CompilerConfig
|
||||||
@@ -671,4 +717,4 @@ internal enum ShaderStage
|
|||||||
MeshShader,
|
MeshShader,
|
||||||
PixelShader,
|
PixelShader,
|
||||||
ComputeShader
|
ComputeShader
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Data;
|
using Ghost.Graphics.Core;
|
||||||
using TerraFX.Interop.DirectX;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -9,25 +8,52 @@ namespace Ghost.Graphics.RHI;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommandBuffer : IDisposable
|
public interface ICommandBuffer : IDisposable
|
||||||
{
|
{
|
||||||
public CommandBufferType Type
|
/// <summary>
|
||||||
|
/// Gets the type of the command buffer.
|
||||||
|
/// </summary>
|
||||||
|
CommandBufferType Type
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEmpty
|
/// <summary>
|
||||||
|
/// Indicates whether the command buffer contains any recorded commands.
|
||||||
|
/// </summary>
|
||||||
|
bool IsEmpty
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the command buffer.
|
||||||
|
/// </summary>
|
||||||
|
string Name
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Begins recording commands into this command buffer
|
/// Begins recording commands into this command buffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Begin();
|
void Begin();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ends recording commands and prepares for submission
|
/// Ends recording commands and prepares for submission
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void End();
|
void End();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the viewport for rendering
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewport">Viewport to set</param>
|
||||||
|
void SetViewport(ViewportDesc viewport);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the scissor rectangle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">Scissor rectangle to set</param>
|
||||||
|
void SetScissorRect(RectDesc rect);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the optional render targets and optional depth target for subsequent rendering operations.
|
/// Sets the optional render targets and optional depth target for subsequent rendering operations.
|
||||||
@@ -39,32 +65,20 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="renderTargets">A read-only span of handles to textures that will be used as render targets.
|
/// <param name="renderTargets">A read-only span of handles to textures that will be used as render targets.
|
||||||
/// The order of handles determines the order in which render targets are bound.</param>
|
/// The order of handles determines the order in which render targets are bound.</param>
|
||||||
/// <param name="depthTarget">A handle to the texture to be used as the depth target. Specify a invalid handle if no depth target is required.</param>
|
/// <param name="depthTarget">A handle to the texture to be used as the depth target. Specify a invalid handle if no depth target is required.</param>
|
||||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget);
|
void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Begins a render pass with the specified render target
|
/// Begins a render pass with the specified render target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="renderTarget">Render target to render into (can be invalid)</param>
|
/// <param name="rtDescs">Render target descriptions</param>
|
||||||
/// <param name="depthTarget">Depth target to use (can be invalid)</param>
|
/// <param name="depthDesc">Depth stencil description</param>
|
||||||
/// <param name="clearColor">Color to clear the render target with</param>
|
/// <param name="allowUAVWrites">Whether UAV writes are allowed during the render pass</param>
|
||||||
public void BeginRenderPass(Handle<Texture> renderTarget, Handle<Texture> depthTarget, Color128 clearColor);
|
void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ends the current render pass
|
/// Ends the current render pass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void EndRenderPass();
|
void EndRenderPass();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the viewport for rendering
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="viewport">Viewport to set</param>
|
|
||||||
public void SetViewport(ViewportDesc viewport);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the scissor rectangle
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">Scissor rectangle to set</param>
|
|
||||||
public void SetScissorRect(RectDesc rect);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inserts a resource barrier for state transitions
|
/// Inserts a resource barrier for state transitions
|
||||||
@@ -72,25 +86,61 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="resource">Resource to transition</param>
|
/// <param name="resource">Resource to transition</param>
|
||||||
/// <param name="before">Current resource state</param>
|
/// <param name="before">Current resource state</param>
|
||||||
/// <param name="after">Target resource state</param>
|
/// <param name="after">Target resource state</param>
|
||||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after);
|
void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the graphics root signature
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rootSignature">Root signature to set</param>
|
|
||||||
public void SetRootSignature(IRootSignature rootSignature);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the pipeline state object
|
/// Sets the pipeline state object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pipelineState">Pipeline state to set</param>
|
/// <param name="pipelineKey">Pipeline state to set</param>
|
||||||
public void SetPipelineState(IShaderPipeline pipelineState);
|
void SetPipelineState(GraphicsPipelineKey pipelineKey);
|
||||||
|
|
||||||
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0);
|
/// <summary>
|
||||||
public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0);
|
/// Sets the constant buffer view for the specified slot in the graphics pipeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slot">The zero-based index of the slot to bind the constant buffer view to.</param>
|
||||||
|
/// <param name="buffer">A graphics buffer to use as the constant buffer view.</param>
|
||||||
|
void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer);
|
||||||
|
|
||||||
public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0);
|
/// <summary>
|
||||||
public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0);
|
/// Binds a vertex buffer to the specified slot for subsequent draw calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slot">The vertex buffer slot to bind to.</param>
|
||||||
|
/// <param name="buffer">The handle to the graphics buffer containing vertex data.</param>
|
||||||
|
/// <param name="offset">The offset in bytes from the start of the buffer.</param>
|
||||||
|
void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds an index buffer for indexed drawing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The handle to the graphics buffer containing index data.</param>
|
||||||
|
/// <param name="type">The type of indices (e.g., 16-bit or 32-bit).</param>
|
||||||
|
/// <param name="offset">The offset in bytes from the start of the buffer.</param>
|
||||||
|
void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the primitive topology to be used for subsequent drawing operations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">The primitive topology that determines how the input vertices are interpreted during rendering.</param>
|
||||||
|
void SetPrimitiveTopology(PrimitiveTopology topology);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Issues a non-indexed draw call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertexCount">Number of vertices to draw.</param>
|
||||||
|
/// <param name="instanceCount">Number of instances to draw.</param>
|
||||||
|
/// <param name="startVertex">Index of the first vertex to draw.</param>
|
||||||
|
/// <param name="startInstance">Index of the first instance to draw.</param>
|
||||||
|
void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Issues an indexed draw call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexCount">Number of indices to draw.</param>
|
||||||
|
/// <param name="instanceCount">Number of instances to draw.</param>
|
||||||
|
/// <param name="startIndex">Index of the first index to draw.</param>
|
||||||
|
/// <param name="baseVertex">Value added to each index before indexing the vertex buffer.</param>
|
||||||
|
/// <param name="startInstance">Index of the first instance to draw.</param>
|
||||||
|
void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispatches compute threads
|
/// Dispatches compute threads
|
||||||
@@ -98,7 +148,20 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="threadGroupCountX">Thread groups in X dimension</param>
|
/// <param name="threadGroupCountX">Thread groups in X dimension</param>
|
||||||
/// <param name="threadGroupCountY">Thread groups in Y dimension</param>
|
/// <param name="threadGroupCountY">Thread groups in Y dimension</param>
|
||||||
/// <param name="threadGroupCountZ">Thread groups in Z dimension</param>
|
/// <param name="threadGroupCountZ">Thread groups in Z dimension</param>
|
||||||
public void Dispatch(uint threadGroupCountX, uint threadGroupCountY = 1, uint threadGroupCountZ = 1);
|
void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispatches mesh shader threads
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="threadGroupCountX">Thread groups in X dimension</param>
|
||||||
|
/// <param name="threadGroupCountY">Thread groups in Y dimension</param>
|
||||||
|
/// <param name="threadGroupCountZ">Thread groups in Z dimension</param>
|
||||||
|
void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispatches ray tracing threads
|
||||||
|
/// </summary>
|
||||||
|
void DispatchRay();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uploads the specified data to the buffer represented by the given handle.
|
/// Uploads the specified data to the buffer represented by the given handle.
|
||||||
@@ -107,7 +170,7 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="buffer">A handle to the buffer that will receive the uploaded data.</param>
|
/// <param name="buffer">A handle to the buffer that will receive the uploaded data.</param>
|
||||||
/// <param name="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type
|
/// <param name="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type
|
||||||
/// <typeparamref name="T"/>.</param>
|
/// <typeparamref name="T"/>.</param>
|
||||||
public void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
||||||
where T : unmanaged;
|
where T : unmanaged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -118,7 +181,7 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param>
|
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param>
|
||||||
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
|
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
|
||||||
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
|
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
|
||||||
public void Upload(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
|
void Upload(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.
|
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.
|
||||||
@@ -128,26 +191,5 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// <param name="destOffset">The byte offset in the destination buffer at which to begin writing. Must be zero or greater.</param>
|
/// <param name="destOffset">The byte offset in the destination buffer at which to begin writing. Must be zero or greater.</param>
|
||||||
/// <param name="srcOffset">The byte offset in the source buffer at which to begin reading. Must be zero or greater.</param>
|
/// <param name="srcOffset">The byte offset in the source buffer at which to begin reading. Must be zero or greater.</param>
|
||||||
/// <param name="numBytes">The number of bytes to copy. If zero, copies the remaining bytes from the source buffer starting at <paramref name="srcOffset"/>.</param>
|
/// <param name="numBytes">The number of bytes to copy. If zero, copies the remaining bytes from the source buffer starting at <paramref name="srcOffset"/>.</param>
|
||||||
public void CopyBuffer(Handle<GraphicsBuffer> dest, Handle<GraphicsBuffer> src, ulong destOffset = 0, ulong srcOffset = 0, ulong numBytes = 0);
|
void CopyBuffer(Handle<GraphicsBuffer> dest, Handle<GraphicsBuffer> src, ulong destOffset = 0, ulong srcOffset = 0, ulong numBytes = 0);
|
||||||
}
|
|
||||||
|
|
||||||
internal static class ResourceStateExtensions
|
|
||||||
{
|
|
||||||
public static D3D12_RESOURCE_STATES ToD3D12States(this ResourceState state)
|
|
||||||
{
|
|
||||||
return state switch
|
|
||||||
{
|
|
||||||
ResourceState.Common or ResourceState.Present => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COMMON,
|
|
||||||
ResourceState.VertexAndConstantBuffer => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER,
|
|
||||||
ResourceState.IndexBuffer => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_INDEX_BUFFER,
|
|
||||||
ResourceState.RenderTarget => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_RENDER_TARGET,
|
|
||||||
ResourceState.UnorderedAccess => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
|
||||||
ResourceState.DepthWrite => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
|
||||||
ResourceState.DepthRead => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_DEPTH_READ,
|
|
||||||
ResourceState.PixelShaderResource => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
||||||
ResourceState.CopyDest => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_DEST,
|
|
||||||
ResourceState.CopySource => D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COPY_SOURCE,
|
|
||||||
_ => throw new ArgumentException($"Unknown resource state: {state}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ public interface IShaderPipeline
|
|||||||
|
|
||||||
public interface IPipelineLibrary
|
public interface IPipelineLibrary
|
||||||
{
|
{
|
||||||
void CompilePass(IPassDescriptor descriptor);
|
/// <summary>
|
||||||
void CompileShader(ShaderDescriptor descriptor);
|
/// Load pipeline library from disk.
|
||||||
void PreCookPipelineState();
|
/// </summary>
|
||||||
|
/// <param name="filePath">File path. If null, load default library.</param>
|
||||||
|
void LoadLibraryFromDisk(string? filePath);
|
||||||
void SaveLibraryToDisk(string filePath);
|
void SaveLibraryToDisk(string filePath);
|
||||||
}
|
GraphicsPipelineKey CompilePassPSO(IPassDescriptor descriptor, ReadOnlySpan<TextureFormat> rtvs, TextureFormat dsv);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
namespace Ghost.Graphics.RHI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Root signature interface
|
|
||||||
/// </summary>
|
|
||||||
public interface IRootSignature : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Root signature name for debugging
|
|
||||||
/// </summary>
|
|
||||||
string Name
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Data;
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -150,8 +150,6 @@ public interface IResourceDatabase
|
|||||||
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
||||||
void ReleaseShader(Identifier<Shader> id);
|
void ReleaseShader(Identifier<Shader> id);
|
||||||
|
|
||||||
// TODO: Use xxhash3 to generate passKey from string id.
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a shader pass to the collection using the specified identifier.
|
/// Adds a shader pass to the collection using the specified identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Data;
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using TerraFX.Interop.DirectX;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
|
||||||
|
|
||||||
internal static class RHIUtility
|
internal static class RHIUtility
|
||||||
{
|
{
|
||||||
@@ -122,4 +120,4 @@ internal static class RHIUtility
|
|||||||
slicePitch = rowPitch * height;
|
slicePitch = rowPitch * height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
using Ghost.Graphics.Contracts;
|
||||||
using Ghost.Graphics.Data;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Ghost.Graphics.Utilities;
|
using Ghost.Graphics.Utilities;
|
||||||
using Ghost.SDL.Compiler;
|
using Ghost.SDL.Compiler;
|
||||||
using Misaki.HighPerformance.Image;
|
using Misaki.HighPerformance.Image;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderPasses;
|
namespace Ghost.Graphics.RenderPasses;
|
||||||
|
|
||||||
@@ -26,12 +26,11 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
"C:/Users/Misaki/Downloads/Im/yande.re 1134666 blue_archive nakamasa_ichika sugarhigh.jpg"
|
"C:/Users/Misaki/Downloads/Im/yande.re 1134666 blue_archive nakamasa_ichika sugarhigh.jpg"
|
||||||
];
|
];
|
||||||
|
|
||||||
public void Initialize(ref readonly RenderingContext ctx, IResourceAllocator resourceAllocator, IPipelineLibrary stateController)
|
public void Initialize(ref readonly RenderingContext ctx, IResourceAllocator resourceAllocator, IPipelineLibrary pipelineLibrary)
|
||||||
{
|
{
|
||||||
var shaderDescriptor = SDLCompiler.CompileShader("F:\\csharp\\GhostEngine\\Ghost.Graphics\\RenderPasses\\ShaderCode.hlsl").GetValueOrThrow();
|
var shaderDescriptor = SDLCompiler.CompileShader("F:\\csharp\\GhostEngine\\Ghost.Graphics\\RenderPasses\\ShaderCode.hlsl").GetValueOrThrow();
|
||||||
|
|
||||||
stateController.CompileShader(shaderDescriptor);
|
var key = pipelineLibrary.CompilePassPSO(shaderDescriptor.passes[0], [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown);
|
||||||
stateController.PreCookPipelineState();
|
|
||||||
|
|
||||||
MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices);
|
MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices);
|
||||||
|
|
||||||
@@ -85,4 +84,4 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Ghost.Graphics.Data;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Utilities;
|
namespace Ghost.Graphics.Utilities;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user