Refactor and enhance resource management and rendering
Updated multiple components to improve encapsulation, maintainability, and performance. Key changes include: - Upgraded package dependencies in project files. - Refactored `Mesh` and `RenderingContext` to use properties and added support for per-object constant buffers. - Improved resource management in `D3D12CommandBuffer`, `D3D12CommandQueue`, and `D3D12ResourceAllocator` with better encapsulation and disposal handling. - Added validation for constant buffer sizes in `D3D12PipelineLibrary`. - Simplified `MeshBuilder` methods to accept allocators and removed hardcoded values. - Enhanced debugging with `GPUResourceLeakException` and resource tracking updates. - Updated shaders and rendering logic for testing, including hardcoded triangle rendering. - Removed redundant base classes and interfaces for cleaner code structure.
This commit is contained in:
@@ -18,9 +18,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Misaki.HighPerformance" Version="1.0.0" />
|
<PackageReference Include="Misaki.HighPerformance" Version="1.0.1" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.1.0" />
|
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.1.0" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.0" />
|
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.1" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
||||||
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
||||||
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.5" />
|
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.5" />
|
||||||
|
|||||||
@@ -64,17 +64,11 @@ internal static unsafe partial class Win32Utility
|
|||||||
if (ptr != null)
|
if (ptr != null)
|
||||||
{
|
{
|
||||||
uPtr = default;
|
uPtr = default;
|
||||||
MemoryLeakException.ThrowIfRefCountNonZero(ptr->Release());
|
ptr->Release();
|
||||||
|
//MemoryLeakException.ThrowIfRefCountNonZero(ptr->Release());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void Assert(this HRESULT hr)
|
|
||||||
{
|
|
||||||
Debug.Assert(hr.SUCCEEDED, hr.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Result ToResult(this HRESULT hr, [CallerArgumentExpression(nameof(hr))] string? op = null)
|
public static Result ToResult(this HRESULT hr, [CallerArgumentExpression(nameof(hr))] string? op = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Behaviors" Version="8.2.250402" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -75,12 +75,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.250402" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
||||||
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||||
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
|
<PackageReference Include="WinUIEx" Version="2.9.0" />
|
||||||
<PackageReference Include="WinUIEx" Version="2.6.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public struct QueryFilter : IDisposable
|
|||||||
UnsafeBitSet absentMask = default;
|
UnsafeBitSet absentMask = default;
|
||||||
|
|
||||||
var result = new UnsafeBitSet(world.EntityManager.EntityCount, allocator);
|
var result = new UnsafeBitSet(world.EntityManager.EntityCount, allocator);
|
||||||
result.SetAll();
|
result.ClearAll();
|
||||||
|
|
||||||
using (AllocationManager.CreateStackScope())
|
using (AllocationManager.CreateStackScope())
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ public struct QueryFilter : IDisposable
|
|||||||
|
|
||||||
if (absentMask.IsCreated)
|
if (absentMask.IsCreated)
|
||||||
{
|
{
|
||||||
result.And(~absentMask);
|
result.ANDC(absentMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
<#@ template language="C#" #>
|
<#@ template language="C#" #>
|
||||||
<#@ output extension=".cs" #>
|
<#@ output extension=".cs" #>
|
||||||
<#@ assembly name="System.Core" #>
|
<#@ assembly name="System.Core" #>
|
||||||
<#@ import namespace="System.Text" #>
|
<#@ import namespace="System.Text" #>
|
||||||
|
|||||||
@@ -46,11 +46,11 @@
|
|||||||
<ProjectCapability Include="Msix" />
|
<ProjectCapability Include="Msix" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="17.14.1" />
|
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="18.0.1" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.9.3" />
|
<PackageReference Include="MSTest.TestAdapter" Version="4.0.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.9.3" />
|
<PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ using Ghost.Graphics.RHI;
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
|
using TerraFX.Interop.WinRT;
|
||||||
|
using WinRT;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Test.Windows;
|
namespace Ghost.Graphics.Test.Windows;
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
GraphicsAPI = GraphicsAPI.Direct3D12
|
GraphicsAPI = GraphicsAPI.Direct3D12
|
||||||
});
|
});
|
||||||
_renderer = _renderSystem.GraphicsEngine.CreateRenderer();
|
_renderer = _renderSystem.GraphicsEngine.CreateRenderer();
|
||||||
|
|
||||||
_swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc((uint)AppWindow.Size.Width, (uint)AppWindow.Size.Height, SwapChainTarget.FromCompositionSurface(Panel)));
|
_swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc((uint)AppWindow.Size.Width, (uint)AppWindow.Size.Height, SwapChainTarget.FromCompositionSurface(Panel)));
|
||||||
_renderer.SetSwapChain(_swapChain);
|
_renderer.SetSwapChain(_swapChain);
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public readonly struct ShaderReflectionData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe interface IShaderCompiler
|
public interface IShaderCompiler : IDisposable
|
||||||
{
|
{
|
||||||
Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator);
|
Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator);
|
||||||
Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor);
|
Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.Contracts;
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
|
||||||
public unsafe readonly struct ISwapChainPanelNative : ISwapChainPanelNative.Interface, IDisposable
|
public unsafe readonly struct ISwapChainPanelNative : ISwapChainPanelNative.Interface, IDisposable
|
||||||
{
|
{
|
||||||
[ComImport]
|
[ComImport]
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ internal struct CBufferCache : IResourceReleasable
|
|||||||
public readonly Handle<GraphicsBuffer> GpuResource => _gpuResource;
|
public readonly Handle<GraphicsBuffer> GpuResource => _gpuResource;
|
||||||
public readonly uint AlignedSize => _alignedSize;
|
public readonly uint AlignedSize => _alignedSize;
|
||||||
|
|
||||||
public unsafe CBufferCache(Handle<GraphicsBuffer> buffer, uint bufferSize)
|
public readonly bool IsCreated => _gpuResource.IsValid && _cpuData.IsCreated;
|
||||||
|
|
||||||
|
public CBufferCache(Handle<GraphicsBuffer> buffer, uint bufferSize)
|
||||||
{
|
{
|
||||||
_alignedSize = (bufferSize + 255u) & ~255u;
|
_alignedSize = (bufferSize + 255u) & ~255u;
|
||||||
|
|
||||||
@@ -65,6 +67,11 @@ public struct Material : IResourceReleasable, IHandleType
|
|||||||
var pass = database.GetShaderPass(shader.GetPassKey(i));
|
var pass = database.GetShaderPass(shader.GetPassKey(i));
|
||||||
var cbufferInfo = pass.CBuffer;
|
var cbufferInfo = pass.CBuffer;
|
||||||
|
|
||||||
|
if (cbufferInfo.SizeInBytes == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var desc = new BufferDesc
|
var desc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = cbufferInfo.SizeInBytes,
|
Size = cbufferInfo.SizeInBytes,
|
||||||
@@ -91,7 +98,7 @@ public struct Material : IResourceReleasable, IHandleType
|
|||||||
public ref struct MaterialAccessor
|
public ref struct MaterialAccessor
|
||||||
{
|
{
|
||||||
private ref Material _materialData;
|
private ref Material _materialData;
|
||||||
private Shader _shader;
|
private readonly Shader _shader;
|
||||||
|
|
||||||
private readonly IResourceDatabase _resourceDatabase;
|
private readonly IResourceDatabase _resourceDatabase;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
using Ghost.Graphics.Utilities;
|
||||||
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;
|
||||||
@@ -10,42 +11,118 @@ namespace Ghost.Graphics.Core;
|
|||||||
|
|
||||||
public struct Mesh : IResourceReleasable, IHandleType
|
public struct Mesh : IResourceReleasable, IHandleType
|
||||||
{
|
{
|
||||||
public UnsafeList<Vertex> vertices;
|
internal bool IsMeshDataDirty
|
||||||
public UnsafeList<uint> indices;
|
{
|
||||||
public AABB boundingBox;
|
get; private set;
|
||||||
public Handle<GraphicsBuffer> vertexBuffer;
|
}
|
||||||
public Handle<GraphicsBuffer> indexBuffer;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the collection of vertices that define the geometry.
|
||||||
|
/// </summary>
|
||||||
|
public UnsafeList<Vertex> Vertices
|
||||||
|
{
|
||||||
|
readonly get => field;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
field = value;
|
||||||
|
VertexCount = value.Count;
|
||||||
|
IsMeshDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the collection of indices that define the order of vertices.
|
||||||
|
/// </summary>
|
||||||
|
public UnsafeList<uint> Indices
|
||||||
|
{
|
||||||
|
readonly get => field;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
field = value;
|
||||||
|
IndexCount = value.Count;
|
||||||
|
IsMeshDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the number of vertices in the mesh.
|
||||||
|
/// </summary>
|
||||||
|
public int VertexCount
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the number of indices in the mesh.
|
||||||
|
/// </summary>
|
||||||
|
public int IndexCount
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the axis-aligned bounding box (AABB) of the mesh.
|
||||||
|
/// </summary>
|
||||||
|
public AABB BoundingBox
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the handle to the vertex buffer on the GPU.
|
||||||
|
/// </summary>
|
||||||
|
public Handle<GraphicsBuffer> VertexBuffer
|
||||||
|
{
|
||||||
|
get; internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the handle to the index buffer on the GPU.
|
||||||
|
/// </summary>
|
||||||
|
public Handle<GraphicsBuffer> IndexBuffer
|
||||||
|
{
|
||||||
|
get; internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the handle to the mesh data buffer on the GPU.
|
||||||
|
/// </summary>
|
||||||
|
public Handle<GraphicsBuffer> ObjectDataBuffer
|
||||||
|
{
|
||||||
|
get; internal set;
|
||||||
|
}
|
||||||
|
|
||||||
public Mesh()
|
public Mesh()
|
||||||
{
|
{
|
||||||
vertexBuffer = Handle<GraphicsBuffer>.Invalid;
|
VertexBuffer = Handle<GraphicsBuffer>.Invalid;
|
||||||
indexBuffer = Handle<GraphicsBuffer>.Invalid;
|
IndexBuffer = Handle<GraphicsBuffer>.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Mesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices, Handle<GraphicsBuffer> vertexBuffer, Handle<GraphicsBuffer> indexBuffer)
|
internal Mesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices, Handle<GraphicsBuffer> vertexBuffer, Handle<GraphicsBuffer> indexBuffer)
|
||||||
{
|
{
|
||||||
this.vertices = new(vertices.Length, Allocator.Persistent);
|
Vertices = new(vertices.Length, Allocator.Persistent);
|
||||||
this.indices = new(indices.Length, Allocator.Persistent);
|
Indices = new(indices.Length, Allocator.Persistent);
|
||||||
this.vertices.CopyFrom(vertices);
|
Vertices.CopyFrom(vertices);
|
||||||
this.indices.CopyFrom(indices);
|
Indices.CopyFrom(indices);
|
||||||
this.vertexBuffer = vertexBuffer;
|
VertexBuffer = vertexBuffer;
|
||||||
this.indexBuffer = indexBuffer;
|
IndexBuffer = indexBuffer;
|
||||||
|
|
||||||
this.ComputeBounds();
|
this.ComputeBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseCpuResources()
|
public readonly void ReleaseCpuResources()
|
||||||
{
|
{
|
||||||
vertices.Dispose();
|
Vertices.Dispose();
|
||||||
indices.Dispose();
|
Indices.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
||||||
{
|
{
|
||||||
ReleaseCpuResources();
|
ReleaseCpuResources();
|
||||||
|
|
||||||
database.ReleaseResource(vertexBuffer.AsResource());
|
database.ReleaseResource(VertexBuffer.AsResource());
|
||||||
database.ReleaseResource(indexBuffer.AsResource());
|
database.ReleaseResource(IndexBuffer.AsResource());
|
||||||
|
database.ReleaseResource(ObjectDataBuffer.AsResource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,21 +133,21 @@ public static class MeshExtension
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void ComputeBounds(ref this Mesh mesh)
|
public static void ComputeBounds(ref this Mesh mesh)
|
||||||
{
|
{
|
||||||
if (mesh.vertices.Count == 0)
|
if (mesh.Vertices.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var min = new float3(float.MaxValue);
|
var min = new float3(float.MaxValue);
|
||||||
var max = new float3(float.MinValue);
|
var max = new float3(float.MinValue);
|
||||||
foreach (var vertex in mesh.vertices)
|
foreach (var vertex in mesh.Vertices)
|
||||||
{
|
{
|
||||||
var pos = vertex.position.xyz;
|
var pos = vertex.position.xyz;
|
||||||
min = math.min(min, pos);
|
min = math.min(min, pos);
|
||||||
max = math.max(max, pos);
|
max = math.max(max, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.boundingBox = new AABB(min, max);
|
mesh.BoundingBox = new AABB(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -81,35 +158,7 @@ public static class MeshExtension
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static void ComputeNormal(ref this Mesh mesh)
|
public static void ComputeNormal(ref this Mesh mesh)
|
||||||
{
|
{
|
||||||
if (!mesh.vertices.IsCreated || mesh.vertices.Count < 3
|
MeshBuilder.ComputeNormal(mesh.Vertices, mesh.Indices);
|
||||||
|| !mesh.indices.IsCreated || mesh.indices.Count < 3)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < mesh.indices.Count; i += 3)
|
|
||||||
{
|
|
||||||
var i0 = mesh.indices[i];
|
|
||||||
var i1 = mesh.indices[i + 1];
|
|
||||||
var i2 = mesh.indices[i + 2];
|
|
||||||
|
|
||||||
var v0 = mesh.vertices[i0];
|
|
||||||
var v1 = mesh.vertices[i1];
|
|
||||||
var v2 = mesh.vertices[i2];
|
|
||||||
|
|
||||||
var edge1 = v1.position - v0.position;
|
|
||||||
var edge2 = v2.position - v0.position;
|
|
||||||
var faceNormal = math.cross(edge1.xyz, edge2.xyz);
|
|
||||||
|
|
||||||
mesh.vertices[i0].normal.xyz += faceNormal;
|
|
||||||
mesh.vertices[i1].normal.xyz += faceNormal;
|
|
||||||
mesh.vertices[i2].normal.xyz += faceNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < mesh.vertices.Count; i++)
|
|
||||||
{
|
|
||||||
mesh.vertices[i].normal = math.normalize(mesh.vertices[i].normal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,53 +169,6 @@ public static class MeshExtension
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static void ComputeTangents(ref this Mesh mesh)
|
public static void ComputeTangents(ref this Mesh mesh)
|
||||||
{
|
{
|
||||||
var bitangents = new float4[mesh.vertices.Count];
|
MeshBuilder.ComputeTangents(mesh.Vertices, mesh.Indices);
|
||||||
|
|
||||||
for (var i = 0; i < mesh.indices.Count; i += 3)
|
|
||||||
{
|
|
||||||
var i0 = mesh.indices[i];
|
|
||||||
var i1 = mesh.indices[i + 1];
|
|
||||||
var i2 = mesh.indices[i + 2];
|
|
||||||
|
|
||||||
var v0 = mesh.vertices[i0];
|
|
||||||
var v1 = mesh.vertices[i1];
|
|
||||||
var v2 = mesh.vertices[i2];
|
|
||||||
|
|
||||||
var uv0 = mesh.vertices[i0].uv;
|
|
||||||
var uv1 = mesh.vertices[i1].uv;
|
|
||||||
var uv2 = mesh.vertices[i2].uv;
|
|
||||||
|
|
||||||
var deltaPos1 = v1.position - v0.position;
|
|
||||||
var deltaPos2 = v2.position - v0.position;
|
|
||||||
var deltaUV1 = uv1 - uv0;
|
|
||||||
var deltaUV2 = uv2 - uv0;
|
|
||||||
|
|
||||||
var r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
|
|
||||||
var tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
|
|
||||||
var bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
|
|
||||||
|
|
||||||
for (var j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
var idx = mesh.indices[i + j];
|
|
||||||
var t = mesh.vertices[idx].tangent;
|
|
||||||
mesh.vertices[idx].tangent.xyz = t.xyz + tangent.xyz;
|
|
||||||
|
|
||||||
bitangents[idx] += bitangent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < mesh.vertices.Count; i++)
|
|
||||||
{
|
|
||||||
var n = mesh.vertices[i].normal;
|
|
||||||
var t = mesh.vertices[i].tangent;
|
|
||||||
|
|
||||||
var proj = n * math.dot(n, t);
|
|
||||||
t = math.normalize(t - proj);
|
|
||||||
|
|
||||||
var b = bitangents[i];
|
|
||||||
var w = math.dot(math.cross(n.xyz, t.xyz), b.xyz) < 0.0f ? -1.0f : 1.0f;
|
|
||||||
|
|
||||||
mesh.vertices[i].tangent = new float4(t.x, t.y, t.z, w);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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;
|
||||||
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
@@ -72,6 +73,11 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
return CreateMesh(vertexList, indexList);
|
return CreateMesh(vertexList, indexList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MaterialAccessor GetMaterialAccessor(Handle<Material> material)
|
||||||
|
{
|
||||||
|
return new MaterialAccessor(material, ResourceDatabase);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Make one memory pool for upload.
|
// TODO: Make one memory pool for upload.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -82,32 +88,32 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic)
|
public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic)
|
||||||
{
|
{
|
||||||
ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
|
ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
|
||||||
var vertexState = ResourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource());
|
var vertexState = ResourceDatabase.GetResourceState(meshData.VertexBuffer.AsResource());
|
||||||
var indexState = ResourceDatabase.GetResourceState(meshData.indexBuffer.AsResource());
|
var indexState = ResourceDatabase.GetResourceState(meshData.IndexBuffer.AsResource());
|
||||||
var needVertexTransition = vertexState != ResourceState.CopyDest;
|
var needVertexTransition = vertexState != ResourceState.CopyDest;
|
||||||
var needIndexTransition = indexState != ResourceState.CopyDest;
|
var needIndexTransition = indexState != ResourceState.CopyDest;
|
||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), indexState, ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
_directCmd.UploadBuffer(meshData.vertexBuffer, meshData.vertices.AsSpan());
|
_directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan());
|
||||||
_directCmd.UploadBuffer(meshData.indexBuffer, meshData.indices.AsSpan());
|
_directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan());
|
||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.IndexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markMeshStatic)
|
if (markMeshStatic)
|
||||||
@@ -116,6 +122,34 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateObjectData(Handle<Mesh> mesh, float4x4 localToWorld)
|
||||||
|
{
|
||||||
|
ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
|
||||||
|
var data = new PerObjectData
|
||||||
|
{
|
||||||
|
localToWorld = localToWorld,
|
||||||
|
worldBoundsMin = meshData.BoundingBox.Min,
|
||||||
|
worldBoundsMax = meshData.BoundingBox.Max,
|
||||||
|
vertexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.VertexBuffer.AsResource()),
|
||||||
|
indexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.IndexBuffer.AsResource()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var bufferHandle = meshData.ObjectDataBuffer.AsResource();
|
||||||
|
var state = ResourceDatabase.GetResourceState(bufferHandle);
|
||||||
|
var needTransition = state != ResourceState.CopyDest;
|
||||||
|
if (needTransition)
|
||||||
|
{
|
||||||
|
_directCmd.ResourceBarrier(bufferHandle, state, ResourceState.CopyDest);
|
||||||
|
}
|
||||||
|
|
||||||
|
_directCmd.UploadBuffer(meshData.ObjectDataBuffer, [data]);
|
||||||
|
|
||||||
|
if (needTransition)
|
||||||
|
{
|
||||||
|
_directCmd.ResourceBarrier(bufferHandle, ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false)
|
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false)
|
||||||
{
|
{
|
||||||
return ResourceAllocator.CreateTexture(in desc, tempResource);
|
return ResourceAllocator.CreateTexture(in desc, tempResource);
|
||||||
@@ -126,13 +160,6 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource());
|
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource());
|
||||||
desc.TextureDescription.Format.GetSurfaceInfo((int)desc.TextureDescription.Width, (int)desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
|
desc.TextureDescription.Format.GetSurfaceInfo((int)desc.TextureDescription.Width, (int)desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
|
||||||
|
|
||||||
var subresourceData = new SubResourceData
|
|
||||||
{
|
|
||||||
pData = data.GetUnsafePtr(),
|
|
||||||
rowPitch = rowPitch,
|
|
||||||
slicePitch = slicePitch
|
|
||||||
};
|
|
||||||
|
|
||||||
var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource());
|
var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource());
|
||||||
var needTransition = sateBefore != ResourceState.CopyDest;
|
var needTransition = sateBefore != ResourceState.CopyDest;
|
||||||
|
|
||||||
@@ -141,7 +168,17 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
_directCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
_directCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
_directCmd.UploadTexture(texture, subresourceData);
|
fixed (byte* pData = data)
|
||||||
|
{
|
||||||
|
var subresourceData = new SubResourceData
|
||||||
|
{
|
||||||
|
pData = pData,
|
||||||
|
rowPitch = rowPitch,
|
||||||
|
slicePitch = slicePitch
|
||||||
|
};
|
||||||
|
|
||||||
|
_directCmd.UploadTexture(texture, subresourceData);
|
||||||
|
}
|
||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
{
|
{
|
||||||
@@ -169,9 +206,14 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
var pipelineKey = hash.GetKey();
|
var pipelineKey = hash.GetKey();
|
||||||
_directCmd.SetPipelineState(pipelineKey);
|
_directCmd.SetPipelineState(pipelineKey);
|
||||||
|
|
||||||
|
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, meshRef.ObjectDataBuffer);
|
||||||
|
|
||||||
// NOTE: We use fixed root signature layout for bindless rendering.
|
// NOTE: We use fixed root signature layout for bindless rendering.
|
||||||
ref var cache = ref materialRef.GetPassCache(passIndex);
|
ref var cache = ref materialRef.GetPassCache(passIndex);
|
||||||
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
|
if (cache.IsCreated)
|
||||||
|
{
|
||||||
|
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
|
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
|
||||||
// TODO: Maybe handle the traditional bindless model?
|
// TODO: Maybe handle the traditional bindless model?
|
||||||
@@ -180,7 +222,7 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX;
|
//var threadGroupCountX = ((uint)meshRef.IndexCount + numThreadsX - 1) / numThreadsX;
|
||||||
_directCmd.DispatchMesh(threadGroupCountX, 1, 1);
|
_directCmd.DispatchMesh(1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,4 +43,14 @@ public static class RootSignatureLayout
|
|||||||
4
|
4
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public struct PerObjectData
|
||||||
|
{
|
||||||
|
public float4x4 localToWorld;
|
||||||
|
public float3 worldBoundsMin;
|
||||||
|
public uint vertexBuffer;
|
||||||
|
public float3 worldBoundsMax;
|
||||||
|
public uint indexBuffer;
|
||||||
|
};
|
||||||
@@ -19,10 +19,11 @@ public class ShaderPass : IResourceReleasable
|
|||||||
{
|
{
|
||||||
_cbufferInfo = info;
|
_cbufferInfo = info;
|
||||||
|
|
||||||
_propertyLookup = new Dictionary<string, int>(info.Properties.Count);
|
var capacity = info.Properties?.Count ?? 0;
|
||||||
for (var i = 0; i < info.Properties.Count; i++)
|
_propertyLookup = new Dictionary<string, int>(capacity);
|
||||||
|
for (var i = 0; i < capacity; i++)
|
||||||
{
|
{
|
||||||
_propertyLookup[info.Properties[i].Name] = i;
|
_propertyLookup[info.Properties![i].Name] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,16 @@ 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.D3D_Alias;
|
||||||
using static TerraFX.Aliases.D3D12_Alias;
|
using static TerraFX.Aliases.D3D12_Alias;
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList10>, ICommandBuffer
|
internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||||
{
|
{
|
||||||
|
private UniquePtr<ID3D12GraphicsCommandList10> _commandList;
|
||||||
private UniquePtr<ID3D12CommandAllocator> _allocator;
|
private UniquePtr<ID3D12CommandAllocator> _allocator;
|
||||||
|
|
||||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||||
@@ -26,12 +28,28 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
|
|
||||||
private ushort _commandCount;
|
private ushort _commandCount;
|
||||||
private bool _isRecording;
|
private bool _isRecording;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public ID3D12GraphicsCommandList10* NativeCommandList => nativeObject.Get();
|
public SharedPtr<ID3D12GraphicsCommandList10> NativeCommandList => _commandList.Get();
|
||||||
|
|
||||||
public CommandBufferType Type => _type;
|
public CommandBufferType Type => _type;
|
||||||
public bool IsEmpty => _commandCount == 0;
|
public bool IsEmpty => _commandCount == 0;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => field;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (field == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
field = value;
|
||||||
|
_commandList.Get()->SetName(value);
|
||||||
|
}
|
||||||
|
} = string.Empty;
|
||||||
|
|
||||||
public D3D12CommandBuffer(
|
public D3D12CommandBuffer(
|
||||||
D3D12RenderDevice device,
|
D3D12RenderDevice device,
|
||||||
D3D12PipelineLibrary stateController,
|
D3D12PipelineLibrary stateController,
|
||||||
@@ -46,11 +64,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ID3D12GraphicsCommandList10* pCommandList = default;
|
ID3D12GraphicsCommandList10* pCommandList = default;
|
||||||
var commandListType = ConvertCommandBufferType(type);
|
var commandListType = ConvertCommandBufferType(type);
|
||||||
|
|
||||||
device.NativeDevice->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator);
|
device.NativeDevice.Get()->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator);
|
||||||
device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
|
device.NativeDevice.Get()->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList);
|
||||||
|
|
||||||
_allocator.Attach(pAllocator);
|
_allocator.Attach(pAllocator);
|
||||||
nativeObject.Attach(pCommandList);
|
_commandList.Attach(pCommandList);
|
||||||
|
|
||||||
_pipelineLibrary = stateController;
|
_pipelineLibrary = stateController;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
@@ -60,6 +78,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~D3D12CommandBuffer()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type)
|
private static D3D12_COMMAND_LIST_TYPE ConvertCommandBufferType(CommandBufferType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
@@ -71,6 +94,12 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void ThrowIfDisposed()
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ThrowIfRecording()
|
private void ThrowIfRecording()
|
||||||
{
|
{
|
||||||
@@ -100,7 +129,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
void ResetCommandList()
|
void ResetCommandList()
|
||||||
{
|
{
|
||||||
ThrowIfFailed(_allocator.Get()->Reset());
|
ThrowIfFailed(_allocator.Get()->Reset());
|
||||||
ThrowIfFailed(nativeObject.Get()->Reset(_allocator.Get(), null));
|
ThrowIfFailed(_commandList.Get()->Reset(_allocator.Get(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBindlessHeap()
|
void SetBindlessHeap()
|
||||||
@@ -108,14 +137,18 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
var heaps = stackalloc ID3D12DescriptorHeap*[2];
|
var heaps = stackalloc ID3D12DescriptorHeap*[2];
|
||||||
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
|
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
|
||||||
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
|
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
|
||||||
nativeObject.Get()->SetDescriptorHeaps(2, heaps);
|
_commandList.Get()->SetDescriptorHeaps(2, heaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
ThrowIfRecording();
|
ThrowIfRecording();
|
||||||
|
|
||||||
ResetCommandList();
|
ResetCommandList();
|
||||||
SetBindlessHeap();
|
|
||||||
|
if (Type == CommandBufferType.Graphics || Type == CommandBufferType.Compute)
|
||||||
|
{
|
||||||
|
SetBindlessHeap();
|
||||||
|
}
|
||||||
|
|
||||||
_commandCount = 0;
|
_commandCount = 0;
|
||||||
_isRecording = true;
|
_isRecording = true;
|
||||||
@@ -126,7 +159,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
|
|
||||||
nativeObject.Get()->Close();
|
_commandList.Get()->Close();
|
||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +170,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var d3d12Rect = new RECT((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);
|
var d3d12Rect = new RECT((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);
|
||||||
nativeObject.Get()->RSSetScissorRects(1, &d3d12Rect);
|
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
|
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
|
||||||
@@ -150,7 +183,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
|
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
|
||||||
before.ToD3D12States(), after.ToD3D12States());
|
before.ToD3D12States(), after.ToD3D12States());
|
||||||
|
|
||||||
nativeObject.Get()->ResourceBarrier(1, &barrier);
|
_commandList.Get()->ResourceBarrier(1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
||||||
@@ -168,17 +201,17 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
var descriptor = _resourceDatabase.GetResourceInfo(handle.AsResource()).viewGroup;
|
var descriptor = _resourceDatabase.GetResourceRecord(handle.AsResource()).viewGroup;
|
||||||
pRtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
|
pRtvHandles[i] = _descriptorAllocator.GetCpuHandle(descriptor.rtv);
|
||||||
}
|
}
|
||||||
|
|
||||||
var pDsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
|
var pDsvHandle = stackalloc D3D12_CPU_DESCRIPTOR_HANDLE[depthTarget.IsValid ? 1 : 0];
|
||||||
if (pDsvHandle != null)
|
if (pDsvHandle != null)
|
||||||
{
|
{
|
||||||
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceInfo(depthTarget.AsResource()).viewGroup.dsv);
|
pDsvHandle[0] = _descriptorAllocator.GetCpuHandle(_resourceDatabase.GetResourceRecord(depthTarget.AsResource()).viewGroup.dsv);
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
|
_commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false)
|
public void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false)
|
||||||
@@ -196,7 +229,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
throw new ArgumentException($"Render target at index {i} is not a valid texture handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
var resourceInfo = _resourceDatabase.GetResourceInfo(rtDesc.Texture.AsResource());
|
var resourceInfo = _resourceDatabase.GetResourceRecord(rtDesc.Texture.AsResource());
|
||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv);
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.rtv);
|
||||||
|
|
||||||
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
|
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
|
||||||
@@ -212,6 +245,10 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
Format = resourceInfo.desc.TextureDescription.Format.ToDXGIFormat(),
|
Format = resourceInfo.desc.TextureDescription.Format.ToDXGIFormat(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
EndingAccess = new D3D12_RENDER_PASS_ENDING_ACCESS
|
||||||
|
{
|
||||||
|
Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -226,7 +263,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.Texture.IsValid ? 1 : 0];
|
var pDsvDesc = stackalloc D3D12_RENDER_PASS_DEPTH_STENCIL_DESC[depthDesc.Texture.IsValid ? 1 : 0];
|
||||||
if (pDsvDesc != null)
|
if (pDsvDesc != null)
|
||||||
{
|
{
|
||||||
var resourceInfo = _resourceDatabase.GetResourceInfo(depthDesc.Texture.AsResource());
|
var resourceInfo = _resourceDatabase.GetResourceRecord(depthDesc.Texture.AsResource());
|
||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv);
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceInfo.viewGroup.dsv);
|
||||||
|
|
||||||
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
|
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
|
||||||
@@ -253,7 +290,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
pDsvDesc[0] = desc;
|
pDsvDesc[0] = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
|
_commandList.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc,
|
||||||
allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE);
|
allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +300,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
nativeObject.Get()->EndRenderPass();
|
_commandList.Get()->EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewport(ViewportDesc viewport)
|
public void SetViewport(ViewportDesc viewport)
|
||||||
@@ -272,8 +309,8 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var d3d12Viewport = new D3D12_VIEWPORT(viewport.Width, viewport.Height, viewport.X, viewport.Y, viewport.MinDepth, viewport.MaxDepth);
|
var d3d12Viewport = new D3D12_VIEWPORT(viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth);
|
||||||
nativeObject.Get()->RSSetViewports(1, &d3d12Viewport);
|
_commandList.Get()->RSSetViewports(1, &d3d12Viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPipelineState(GraphicsPipelineKey pipelineKey)
|
public void SetPipelineState(GraphicsPipelineKey pipelineKey)
|
||||||
@@ -288,9 +325,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
Logger.LogError($"Failed to get graphics pipeline state object for key {pipelineKey}: {psor.Status}");
|
Logger.LogError($"Failed to get graphics pipeline state object for key {pipelineKey}: {psor.Status}");
|
||||||
#endif
|
#endif
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject.Get()->SetPipelineState(psor.Value);
|
_commandList.Get()->SetGraphicsRootSignature(_pipelineLibrary.DefaultRootSignature);
|
||||||
|
_commandList.Get()->SetPipelineState(psor.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer)
|
public void SetConstantBufferView(uint slot, Handle<GraphicsBuffer> buffer)
|
||||||
@@ -300,7 +339,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||||
nativeObject.Get()->SetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress());
|
_commandList.Get()->SetGraphicsRootConstantBufferView(slot, resource.Get()->GetGPUVirtualAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
|
public void SetVertexBuffer(uint slot, Handle<GraphicsBuffer> buffer, ulong offset = 0)
|
||||||
@@ -309,15 +348,15 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||||
var vbView = new D3D12_VERTEX_BUFFER_VIEW
|
var vbView = new D3D12_VERTEX_BUFFER_VIEW
|
||||||
{
|
{
|
||||||
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
|
BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset,
|
||||||
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
|
SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset),
|
||||||
StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).BufferDescription.Stride
|
StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).BufferDescription.Stride
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeObject.Get()->IASetVertexBuffers(slot, 1, &vbView);
|
_commandList.Get()->IASetVertexBuffers(slot, 1, &vbView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0)
|
public void SetIndexBuffer(Handle<GraphicsBuffer> buffer, IndexType type, ulong offset = 0)
|
||||||
@@ -326,15 +365,15 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
var resource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||||
var ibView = new D3D12_INDEX_BUFFER_VIEW
|
var ibView = new D3D12_INDEX_BUFFER_VIEW
|
||||||
{
|
{
|
||||||
BufferLocation = pResource->GetGPUVirtualAddress() + offset,
|
BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset,
|
||||||
SizeInBytes = (uint)(pResource->GetDesc().Width - offset),
|
SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset),
|
||||||
Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT
|
Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeObject.Get()->IASetIndexBuffer(&ibView);
|
_commandList.Get()->IASetIndexBuffer(&ibView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||||
@@ -351,7 +390,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
_ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
|
_ => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeObject.Get()->IASetPrimitiveTopology(d3d12Topology);
|
_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)
|
||||||
@@ -360,7 +399,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
nativeObject.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance);
|
_commandList.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0)
|
public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0)
|
||||||
@@ -369,7 +408,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
nativeObject.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
_commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||||
@@ -378,7 +417,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
nativeObject.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
_commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ)
|
||||||
@@ -387,7 +426,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
nativeObject.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
_commandList.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchRay()
|
public void DispatchRay()
|
||||||
@@ -398,7 +437,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
// ThrowIfNotRecording();
|
// ThrowIfNotRecording();
|
||||||
// IncrementCommandCount();
|
// IncrementCommandCount();
|
||||||
|
|
||||||
// nativeObject.Get()->DispatchRays();
|
// _device.Get()->DispatchRays();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
|
||||||
@@ -411,19 +450,19 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
var sizeInBytes = (uint)(data.Length * sizeof(T));
|
var sizeInBytes = (uint)(data.Length * sizeof(T));
|
||||||
|
|
||||||
var uploadHandle = _resourceAllocator.CreateUploadBuffer(sizeInBytes);
|
var uploadHandle = _resourceAllocator.CreateUploadBuffer(sizeInBytes);
|
||||||
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||||
|
|
||||||
void* pMappedData;
|
void* pMappedData;
|
||||||
pUploadResource->Map(0, null, &pMappedData);
|
uploadResource.Get()->Map(0, null, &pMappedData);
|
||||||
fixed (T* pData = data)
|
fixed (T* pData = data)
|
||||||
{
|
{
|
||||||
MemoryUtility.MemCpy(pMappedData, pData, sizeInBytes);
|
MemoryUtility.MemCpy(pData, pMappedData, sizeInBytes);
|
||||||
}
|
}
|
||||||
pUploadResource->Unmap(0, null);
|
uploadResource.Get()->Unmap(0, null);
|
||||||
|
|
||||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||||
|
|
||||||
nativeObject.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes);
|
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
||||||
@@ -432,10 +471,10 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var pResource = _resourceDatabase.GetResource(texture.AsResource());
|
var resource = _resourceDatabase.GetResource(texture.AsResource());
|
||||||
|
|
||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = resource.Get()->GetDesc();
|
||||||
var requiredSize = GetRequiredIntermediateSize(pResource, 0, (uint)subresources.Length);
|
var requiredSize = GetRequiredIntermediateSize(resource, 0, (uint)subresources.Length);
|
||||||
|
|
||||||
var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize);
|
var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize);
|
||||||
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||||
@@ -452,8 +491,8 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateSubresources(
|
UpdateSubresources(
|
||||||
(ID3D12GraphicsCommandList*)nativeObject.Get(),
|
(ID3D12GraphicsCommandList*)_commandList.Get(),
|
||||||
pResource,
|
resource,
|
||||||
pUploadResource,
|
pUploadResource,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -476,17 +515,17 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
|
|
||||||
if (numBytes == 0)
|
if (numBytes == 0)
|
||||||
{
|
{
|
||||||
nativeObject.Get()->CopyResource(pDestResource, pSrcResource);
|
_commandList.Get()->CopyResource(pDestResource, pSrcResource);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nativeObject.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes);
|
_commandList.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -496,9 +535,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
throw new InvalidOperationException("Command buffer is still recording");
|
throw new InvalidOperationException("Command buffer is still recording");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_commandList.Dispose();
|
||||||
_allocator.Dispose();
|
_allocator.Dispose();
|
||||||
_commandCount = 0;
|
_commandCount = 0;
|
||||||
|
|
||||||
base.Dispose(disposing);
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
@@ -10,18 +9,21 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12 implementation of command queue interface
|
/// D3D12 implementation of command queue interface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, ICommandQueue
|
internal unsafe class D3D12CommandQueue : ICommandQueue
|
||||||
{
|
{
|
||||||
|
private UniquePtr<ID3D12CommandQueue> _commandQueue;
|
||||||
private UniquePtr<ID3D12Fence1> _fence;
|
private UniquePtr<ID3D12Fence1> _fence;
|
||||||
|
|
||||||
private readonly AutoResetEvent _fenceEvent;
|
private readonly AutoResetEvent _fenceEvent;
|
||||||
private ulong _fenceValue;
|
private ulong _fenceValue;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public CommandQueueType Type
|
public CommandQueueType Type
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ID3D12CommandQueue* NativeQueue => nativeObject.Get();
|
public SharedPtr<ID3D12CommandQueue> NativeQueue => _commandQueue.Get();
|
||||||
|
|
||||||
public D3D12CommandQueue(ID3D12Device14* pDevice, CommandQueueType type)
|
public D3D12CommandQueue(ID3D12Device14* pDevice, CommandQueueType type)
|
||||||
{
|
{
|
||||||
@@ -41,10 +43,15 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
ThrowIfFailed(pDevice->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue));
|
ThrowIfFailed(pDevice->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue));
|
||||||
ThrowIfFailed(pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence));
|
ThrowIfFailed(pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence));
|
||||||
|
|
||||||
nativeObject.Attach(pQueue);
|
_commandQueue.Attach(pQueue);
|
||||||
_fence.Attach(pFence);
|
_fence.Attach(pFence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~D3D12CommandQueue()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private static D3D12_COMMAND_LIST_TYPE ConvertCommandQueueType(CommandQueueType type)
|
private static D3D12_COMMAND_LIST_TYPE ConvertCommandQueueType(CommandQueueType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
@@ -58,7 +65,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
|
|
||||||
public void Submit(ICommandBuffer commandBuffer)
|
public void Submit(ICommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (commandBuffer.IsEmpty)
|
if (commandBuffer.IsEmpty)
|
||||||
{
|
{
|
||||||
@@ -68,8 +75,8 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
if (commandBuffer is D3D12CommandBuffer d3d12CommandBuffer)
|
if (commandBuffer is D3D12CommandBuffer d3d12CommandBuffer)
|
||||||
{
|
{
|
||||||
var commandList = d3d12CommandBuffer.NativeCommandList;
|
var commandList = d3d12CommandBuffer.NativeCommandList;
|
||||||
var commandListPtr = (ID3D12CommandList*)commandList;
|
var commandListPtr = (ID3D12CommandList*)commandList.Get();
|
||||||
nativeObject.Get()->ExecuteCommandLists(1, &commandListPtr);
|
_commandQueue.Get()->ExecuteCommandLists(1, &commandListPtr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -79,7 +86,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
|
|
||||||
public void Submit(params ReadOnlySpan<ICommandBuffer> commandBuffers)
|
public void Submit(params ReadOnlySpan<ICommandBuffer> commandBuffers)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
Span<int> executableIndices = stackalloc int[commandBuffers.Length];
|
Span<int> executableIndices = stackalloc int[commandBuffers.Length];
|
||||||
executableIndices.Fill(-1);
|
executableIndices.Fill(-1);
|
||||||
@@ -107,7 +114,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
|
|
||||||
if (commandBuffers[cmdIndex] is D3D12CommandBuffer d3d12CommandBuffer)
|
if (commandBuffers[cmdIndex] is D3D12CommandBuffer d3d12CommandBuffer)
|
||||||
{
|
{
|
||||||
ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList;
|
ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList.Get();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -117,21 +124,21 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
currentIndex++;
|
currentIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists);
|
_commandQueue.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong Signal(ulong value)
|
public ulong Signal(ulong value)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
_fenceValue = value;
|
_fenceValue = value;
|
||||||
nativeObject.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue);
|
_commandQueue.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue);
|
||||||
return _fenceValue;
|
return _fenceValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitForValue(ulong value)
|
public void WaitForValue(ulong value)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (_fence.Get()->GetCompletedValue() < value)
|
if (_fence.Get()->GetCompletedValue() < value)
|
||||||
{
|
{
|
||||||
@@ -145,28 +152,30 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, IComm
|
|||||||
|
|
||||||
public ulong GetCompletedValue()
|
public ulong GetCompletedValue()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
return _fence.Get()->GetCompletedValue();
|
return _fence.Get()->GetCompletedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitIdle()
|
public void WaitIdle()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var fenceValue = Signal(Interlocked.Increment(ref _fenceValue));
|
var fenceValue = Signal(Interlocked.Increment(ref _fenceValue));
|
||||||
WaitForValue(fenceValue);
|
WaitForValue(fenceValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fenceEvent?.Dispose();
|
_commandQueue.Dispose();
|
||||||
_fence.Dispose();
|
_fence.Dispose();
|
||||||
|
_fenceEvent?.Dispose();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
public ISwapChain CreateSwapChain(SwapChainDesc desc)
|
public ISwapChain CreateSwapChain(SwapChainDesc desc)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
return new D3D12SwapChain(_resourceDatabase, _device.DXGIFactory, ((D3D12CommandQueue)_device.GraphicsQueue).NativeQueue, desc);
|
return new D3D12SwapChain(_resourceDatabase, _descriptorAllocator, _device, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginFrame()
|
public void BeginFrame()
|
||||||
@@ -152,6 +152,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
_resourceDatabase.Dispose();
|
_resourceDatabase.Dispose();
|
||||||
|
|
||||||
_descriptorAllocator.Dispose();
|
_descriptorAllocator.Dispose();
|
||||||
|
_shaderCompiler.Dispose();
|
||||||
_device.Dispose();
|
_device.Dispose();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
_debugLayer.Dispose();
|
_debugLayer.Dispose();
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
using Misaki.HighPerformance.LowLevel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using TerraFX.Interop.DirectX;
|
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
|
||||||
|
|
||||||
internal abstract class D3D12RHIObject : IRHIObject
|
|
||||||
{
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
} = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal abstract unsafe class D3D12Object<T> : IRHIObject, IDisposable
|
|
||||||
where T : unmanaged, ID3D12Object.Interface
|
|
||||||
{
|
|
||||||
private bool _disposed;
|
|
||||||
private string _name = string.Empty;
|
|
||||||
|
|
||||||
protected UniquePtr<T> nativeObject;
|
|
||||||
|
|
||||||
protected bool Disposed => _disposed;
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get => _name;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_name == value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_name = value;
|
|
||||||
if (nativeObject.Get() != null)
|
|
||||||
{
|
|
||||||
nativeObject.Get()->SetName(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~D3D12Object()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
protected void ThrowIfDisposed()
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeObject.Dispose();
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal abstract class IUnknownObject<T> : IRHIObject, IDisposable
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
private bool _disposed;
|
|
||||||
private string _name = string.Empty;
|
|
||||||
|
|
||||||
protected UniquePtr<T> nativeObject;
|
|
||||||
|
|
||||||
protected bool Disposed => _disposed;
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get => _name;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_name == value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_name = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~IUnknownObject()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
protected void ThrowIfDisposed()
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeObject.Dispose();
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,7 +31,7 @@ internal struct D3D12PipelineState : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||||
{
|
{
|
||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||||
@@ -153,7 +153,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
ID3D12RootSignature* pRootSignature = default;
|
ID3D12RootSignature* pRootSignature = default;
|
||||||
ThrowIfFailed(_device.NativeDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
|
ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
|
||||||
__uuidof(pRootSignature), (void**)&pRootSignature));
|
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||||
|
|
||||||
_defaultRootSignature.Attach(pRootSignature);
|
_defaultRootSignature.Attach(pRootSignature);
|
||||||
@@ -183,12 +183,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
var fileBytes = File.ReadAllBytes(filePath!);
|
var fileBytes = File.ReadAllBytes(filePath!);
|
||||||
fixed (byte* pFileBytes = fileBytes)
|
fixed (byte* pFileBytes = fileBytes)
|
||||||
{
|
{
|
||||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary));
|
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary));
|
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary));
|
||||||
}
|
}
|
||||||
|
|
||||||
_library.Attach(pLibrary);
|
_library.Attach(pLibrary);
|
||||||
@@ -213,18 +213,26 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
|
|
||||||
private static Result<CBufferInfo> ValidateReflectionData(ShaderReflectionData reflectionData)
|
private static Result<CBufferInfo> ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||||
{
|
{
|
||||||
CBufferInfo cbufferInfo;
|
var cbufferInfo = default(CBufferInfo);
|
||||||
|
|
||||||
foreach (var info in reflectionData.ResourcesBindings)
|
foreach (var info in reflectionData.ResourcesBindings)
|
||||||
{
|
{
|
||||||
if (info.BindPoint > 3)
|
if (info.BindPoint >= RootSignatureLayout.ROOT_PARAMETER_COUNT)
|
||||||
{
|
{
|
||||||
return Result.Failure($"Resource binding point {info.BindPoint} is out of range. Only binding points 0-3 are supported in the current root signature.");
|
return Result.Failure($"Resource binding point {info.BindPoint} is out of range. Only binding points 0-3 are supported in the current root signature.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.Type != ShaderInputType.ConstantBuffer)
|
if (info.Type != ShaderInputType.ConstantBuffer)
|
||||||
{
|
{
|
||||||
return Result.Failure($"Resource binding type {info.Type} is not supported. Only constant buffers are supported in the current root signature.");
|
return Result.Failure($"Resource binding type {info.Type} is not supported. Please consider using bindless resources for buffers, textures and samplers.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.BindPoint == RootSignatureLayout.PER_OBJECT_BUFFER_SLOT)
|
||||||
|
{
|
||||||
|
if (info.Size != sizeof(PerObjectData))
|
||||||
|
{
|
||||||
|
return Result.Failure($"Per-object constant buffer size mismatch. Expected size: {sizeof(PerObjectData)}, Actual size: {info.Size}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.BindPoint == RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT)
|
if (info.BindPoint == RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT)
|
||||||
@@ -237,19 +245,15 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
SizeInBytes = info.Size,
|
SizeInBytes = info.Size,
|
||||||
Properties = info.Properties ?? Array.Empty<CBufferPropertyInfo>(),
|
Properties = info.Properties ?? Array.Empty<CBufferPropertyInfo>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.Success(cbufferInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Failure("Per-material constant buffer not found in shader reflection data.");
|
return Result.Success(cbufferInfo);
|
||||||
|
|
||||||
// TODO: Validate Cbuffer sizes and bindings.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static D3D12_COMPARISON_FUNC ToD3DCompare(ZTestOptions z) => z switch
|
private static D3D12_COMPARISON_FUNC ToD3DCompare(ZTestOptions z) => z switch
|
||||||
{
|
{
|
||||||
ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_ALWAYS,
|
ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_NEVER,
|
||||||
ZTestOptions.Less => D3D12_COMPARISON_FUNC_LESS,
|
ZTestOptions.Less => D3D12_COMPARISON_FUNC_LESS,
|
||||||
ZTestOptions.LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
ZTestOptions.LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
||||||
ZTestOptions.Equal => D3D12_COMPARISON_FUNC_EQUAL,
|
ZTestOptions.Equal => D3D12_COMPARISON_FUNC_EQUAL,
|
||||||
@@ -284,7 +288,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message);
|
return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr.Value != psr.Value)
|
if (msr.Value.Properties != null
|
||||||
|
&& msr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||||
{
|
{
|
||||||
return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match.");
|
return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match.");
|
||||||
}
|
}
|
||||||
@@ -297,12 +302,14 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message);
|
return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tsr.Value != msr.Value)
|
if (tsr.Value.Properties != null
|
||||||
|
&& tsr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||||
{
|
{
|
||||||
return Result.Failure("Task shader and mesh shader constant buffer layouts do not match.");
|
return Result.Failure("Task shader and pixel shader constant buffer layouts do not match.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ts and ms may not use per material cbuffer at all, so we return the psr value.
|
||||||
return psr.Value;
|
return psr.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +403,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable
|
|||||||
if (hr == E.E_INVALIDARG)
|
if (hr == E.E_INVALIDARG)
|
||||||
{
|
{
|
||||||
// Pipeline not found in the library, create a new one.
|
// Pipeline not found in the library, create a new one.
|
||||||
ThrowIfFailed(_device.NativeDevice->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||||
ThrowIfFailed(_library.Get()->StorePipeline(pKeyStr, pPipelineState));
|
ThrowIfFailed(_library.Get()->StorePipeline(pKeyStr, pPipelineState));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12 implementation of the render device interface
|
/// D3D12 implementation of the render device interface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDevice
|
internal unsafe class D3D12RenderDevice : IRenderDevice
|
||||||
{
|
{
|
||||||
|
private UniquePtr<ID3D12Device14> _device;
|
||||||
private UniquePtr<IDXGIFactory7> _dxgiFactory;
|
private UniquePtr<IDXGIFactory7> _dxgiFactory;
|
||||||
private UniquePtr<IDXGIAdapter1> _adapter;
|
private UniquePtr<IDXGIAdapter1> _adapter;
|
||||||
|
|
||||||
@@ -21,21 +22,35 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
private readonly D3D12CommandQueue _computeQueue;
|
private readonly D3D12CommandQueue _computeQueue;
|
||||||
private readonly D3D12CommandQueue _copyQueue;
|
private readonly D3D12CommandQueue _copyQueue;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public ICommandQueue GraphicsQueue => _graphicsQueue;
|
public ICommandQueue GraphicsQueue => _graphicsQueue;
|
||||||
public ICommandQueue ComputeQueue => _computeQueue;
|
public ICommandQueue ComputeQueue => _computeQueue;
|
||||||
public ICommandQueue CopyQueue => _copyQueue;
|
public ICommandQueue CopyQueue => _copyQueue;
|
||||||
|
|
||||||
public IDXGIFactory7* DXGIFactory => _dxgiFactory.Get();
|
public SharedPtr<IDXGIFactory7> DXGIFactory => _dxgiFactory.Get();
|
||||||
public ID3D12Device14* NativeDevice => nativeObject.Get();
|
public SharedPtr<ID3D12Device14> NativeDevice => _device.Get();
|
||||||
public IDXGIAdapter1* Adapter => _adapter.Get();
|
public SharedPtr<IDXGIAdapter1> Adapter => _adapter.Get();
|
||||||
|
public SharedPtr<ID3D12CommandQueue> NativeGraphicsQueue => _graphicsQueue.NativeQueue;
|
||||||
|
public SharedPtr<ID3D12CommandQueue> NativeComputeQueue => _computeQueue.NativeQueue;
|
||||||
|
public SharedPtr<ID3D12CommandQueue> NativeCopyQueue => _copyQueue.NativeQueue;
|
||||||
|
|
||||||
public D3D12RenderDevice()
|
public D3D12RenderDevice()
|
||||||
{
|
{
|
||||||
|
IDXGIFactory7* pFactory = default;
|
||||||
|
#if DEBUG
|
||||||
|
ThrowIfFailed(CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory));
|
||||||
|
#else
|
||||||
|
ThrowIfFailed(CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_dxgiFactory.Attach(pFactory);
|
||||||
|
|
||||||
InitializeDevice();
|
InitializeDevice();
|
||||||
|
|
||||||
_graphicsQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Graphics);
|
_graphicsQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Graphics);
|
||||||
_computeQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Compute);
|
_computeQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Compute);
|
||||||
_copyQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Copy);
|
_copyQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D12RenderDevice()
|
~D3D12RenderDevice()
|
||||||
@@ -45,15 +60,6 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
|
|
||||||
private void InitializeDevice()
|
private void InitializeDevice()
|
||||||
{
|
{
|
||||||
IDXGIFactory7* pFactory = default;
|
|
||||||
#if DEBUG
|
|
||||||
CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory);
|
|
||||||
#else
|
|
||||||
CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_dxgiFactory.Attach(pFactory);
|
|
||||||
|
|
||||||
ID3D12Device14* pDevice = default;
|
ID3D12Device14* pDevice = default;
|
||||||
IDXGIAdapter1* pAdapter = default;
|
IDXGIAdapter1* pAdapter = default;
|
||||||
|
|
||||||
@@ -86,17 +92,17 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject.Attach(pDevice);
|
_device.Attach(pDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeatureSupport GetFeatureSupport()
|
public FeatureSupport GetFeatureSupport()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
FeatureSupport support = FeatureSupport.None;
|
FeatureSupport support = FeatureSupport.None;
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
||||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||||
{
|
{
|
||||||
if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3)
|
if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3)
|
||||||
{
|
{
|
||||||
@@ -105,7 +111,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default;
|
||||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED)
|
||||||
{
|
{
|
||||||
if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED)
|
if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED)
|
||||||
{
|
{
|
||||||
@@ -114,7 +120,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = default;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = default;
|
||||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED)
|
||||||
{
|
{
|
||||||
if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED)
|
if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED)
|
||||||
{
|
{
|
||||||
@@ -123,7 +129,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = default;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = default;
|
||||||
if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED)
|
||||||
{
|
{
|
||||||
if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED)
|
if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED)
|
||||||
{
|
{
|
||||||
@@ -139,9 +145,9 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
return support;
|
return support;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -150,9 +156,11 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
|
|||||||
_computeQueue.Dispose();
|
_computeQueue.Dispose();
|
||||||
_copyQueue.Dispose();
|
_copyQueue.Dispose();
|
||||||
|
|
||||||
|
_device.Dispose();
|
||||||
_dxgiFactory.Dispose();
|
_dxgiFactory.Dispose();
|
||||||
_adapter.Dispose();
|
_adapter.Dispose();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,16 +10,17 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12 implementation of the renderer interface using RHI abstractions
|
/// D3D12 implementation of the renderer interface using RHI abstractions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class D3D12Renderer : IRenderer
|
internal class D3D12Renderer : IRenderer
|
||||||
{
|
{
|
||||||
private struct FrameResource : IDisposable
|
private struct FrameResource : IDisposable
|
||||||
{
|
{
|
||||||
public ICommandBuffer commandBuffer;
|
public ICommandBuffer commandBuffer;
|
||||||
public ulong fenceValue;
|
public ulong fenceValue;
|
||||||
|
|
||||||
public FrameResource(D3D12GraphicsEngine graphicsEngine)
|
public FrameResource(D3D12GraphicsEngine graphicsEngine, int index)
|
||||||
{
|
{
|
||||||
commandBuffer = graphicsEngine.CreateCommandBuffer();
|
commandBuffer = graphicsEngine.CreateCommandBuffer();
|
||||||
|
commandBuffer.Name = $"Frame Command Buffer {index}";
|
||||||
fenceValue = 0;
|
fenceValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
_frameResources = new FrameResource[D3D12PipelineResource.BACK_BUFFER_COUNT];
|
_frameResources = new FrameResource[D3D12PipelineResource.BACK_BUFFER_COUNT];
|
||||||
for (var i = 0; i < _frameResources.Length; i++)
|
for (var i = 0; i < _frameResources.Length; i++)
|
||||||
{
|
{
|
||||||
_frameResources[i] = new FrameResource(graphicsEngine);
|
_frameResources[i] = new FrameResource(graphicsEngine, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderTarget = Handle<Texture>.Invalid;
|
_renderTarget = Handle<Texture>.Invalid;
|
||||||
@@ -108,6 +109,12 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
CreateOffScreenRenderTarget(swapChain.Width, swapChain.Height);
|
CreateOffScreenRenderTarget(swapChain.Width, swapChain.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newSize = swapChain != null ? new uint2(swapChain.Width, swapChain.Height) : _currentSize;
|
||||||
|
if (!math.all(newSize == _currentSize))
|
||||||
|
{
|
||||||
|
RequestResize(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
_swapChain = swapChain;
|
_swapChain = swapChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,9 +178,22 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
frame.commandBuffer.Begin();
|
frame.commandBuffer.Begin();
|
||||||
|
|
||||||
// NOTE: Temperary solution: render directly to the swap chain back buffer if available.
|
// NOTE: Temperary solution: render directly to the swap chain back buffer if available.
|
||||||
|
// HACK: This is hard coded for testing purposes only.
|
||||||
|
|
||||||
var rt = _swapChain?.GetCurrentBackBuffer() ?? _renderTarget;
|
var rt = _swapChain?.GetCurrentBackBuffer() ?? _renderTarget;
|
||||||
|
|
||||||
|
if(_swapChain != null)
|
||||||
|
{
|
||||||
|
frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
|
||||||
|
}
|
||||||
|
|
||||||
RenderScene(rt, frame.commandBuffer);
|
RenderScene(rt, frame.commandBuffer);
|
||||||
|
|
||||||
|
if (_swapChain != null)
|
||||||
|
{
|
||||||
|
frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.RenderTarget, ResourceState.Present);
|
||||||
|
}
|
||||||
|
|
||||||
// if (_swapChain != null)
|
// if (_swapChain != null)
|
||||||
// {
|
// {
|
||||||
// var backBufferRT = _swapChain.GetCurrentBackBuffer();
|
// var backBufferRT = _swapChain.GetCurrentBackBuffer();
|
||||||
@@ -196,12 +216,14 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
{
|
{
|
||||||
var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f };
|
var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f };
|
||||||
|
|
||||||
Span<PassRenderTargetDesc> rtDesc = stackalloc PassRenderTargetDesc[1];
|
Span<PassRenderTargetDesc> rtDesc =
|
||||||
rtDesc[0] = new PassRenderTargetDesc
|
[
|
||||||
{
|
new PassRenderTargetDesc
|
||||||
Texture = target,
|
{
|
||||||
ClearColor = clearColor,
|
Texture = target,
|
||||||
};
|
ClearColor = clearColor,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
var depthDesc = new PassDepthStencilDesc
|
var depthDesc = new PassDepthStencilDesc
|
||||||
{
|
{
|
||||||
@@ -217,11 +239,10 @@ internal unsafe class D3D12Renderer : IRenderer
|
|||||||
_pass.Initialize(ref ctx);
|
_pass.Initialize(ref ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
|
||||||
|
|
||||||
var viewport = new ViewportDesc { Width = _currentSize.x, Height = _currentSize.y, MinDepth = 0, MaxDepth = 1 };
|
var viewport = new ViewportDesc { Width = _currentSize.x, Height = _currentSize.y, MinDepth = 0, MaxDepth = 1 };
|
||||||
var scissor = new RectDesc { Right = _currentSize.x, Bottom = _currentSize.y };
|
var scissor = new RectDesc { Right = _currentSize.x, Bottom = _currentSize.y };
|
||||||
|
|
||||||
|
cmd.BeginRenderPass(rtDesc, depthDesc, false);
|
||||||
cmd.SetViewport(viewport);
|
cmd.SetViewport(viewport);
|
||||||
cmd.SetScissorRect(scissor);
|
cmd.SetScissorRect(scissor);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Ghost.Core.Graphics;
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -132,13 +133,13 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = pResource->GetDesc();
|
||||||
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
|
var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC
|
||||||
{
|
{
|
||||||
Format = resourceDesc.Format,
|
|
||||||
ViewDimension = D3D12_SRV_DIMENSION_BUFFER,
|
ViewDimension = D3D12_SRV_DIMENSION_BUFFER,
|
||||||
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
|
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isRaw)
|
if (isRaw)
|
||||||
{
|
{
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||||
srvDesc.Buffer.FirstElement = 0;
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
||||||
srvDesc.Buffer.StructureByteStride = 0;
|
srvDesc.Buffer.StructureByteStride = 0;
|
||||||
@@ -146,6 +147,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
}
|
}
|
||||||
else // Assumes Structured
|
else // Assumes Structured
|
||||||
{
|
{
|
||||||
|
srvDesc.Format = resourceDesc.Format;
|
||||||
srvDesc.Buffer.FirstElement = 0;
|
srvDesc.Buffer.FirstElement = 0;
|
||||||
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
||||||
srvDesc.Buffer.StructureByteStride = stride;
|
srvDesc.Buffer.StructureByteStride = stride;
|
||||||
@@ -406,12 +408,12 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
var resourceDesc = pResource->GetDesc();
|
var resourceDesc = pResource->GetDesc();
|
||||||
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
|
var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC
|
||||||
{
|
{
|
||||||
Format = resourceDesc.Format,
|
|
||||||
ViewDimension = D3D12_UAV_DIMENSION_BUFFER,
|
ViewDimension = D3D12_UAV_DIMENSION_BUFFER,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isRaw)
|
if (isRaw)
|
||||||
{
|
{
|
||||||
|
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||||
uavDesc.Buffer.FirstElement = 0;
|
uavDesc.Buffer.FirstElement = 0;
|
||||||
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u);
|
||||||
uavDesc.Buffer.StructureByteStride = 0;
|
uavDesc.Buffer.StructureByteStride = 0;
|
||||||
@@ -419,6 +421,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
}
|
}
|
||||||
else // Assumes Structured
|
else // Assumes Structured
|
||||||
{
|
{
|
||||||
|
uavDesc.Format = resourceDesc.Format;
|
||||||
uavDesc.Buffer.FirstElement = 0;
|
uavDesc.Buffer.FirstElement = 0;
|
||||||
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride);
|
||||||
uavDesc.Buffer.StructureByteStride = stride;
|
uavDesc.Buffer.StructureByteStride = stride;
|
||||||
@@ -521,6 +524,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
|
|
||||||
// Default to Common, but check for specific roles
|
// Default to Common, but check for specific roles
|
||||||
var state = D3D12_RESOURCE_STATE_COMMON;
|
var state = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
return state;
|
||||||
|
|
||||||
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
|
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
|
||||||
{
|
{
|
||||||
@@ -591,8 +595,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
// TODO: Thread safety for resource allocator
|
// TODO: Thread safety for resource allocator
|
||||||
// A common solution is to use ticket. Each pAllocation request create a ticket and put it into a thread-safe queue. A dedicated thread process the queue and fulfill the requests.
|
// A common solution is to use ticket. Each pAllocation request create a ticket and put it into a thread-safe queue. A dedicated thread process the queue and fulfill the requests.
|
||||||
|
|
||||||
internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D12MA_Allocator>, IResourceAllocator
|
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||||
{
|
{
|
||||||
|
private UniquePtr<D3D12MA_Allocator> _d3d12MA;
|
||||||
|
|
||||||
private readonly IFenceSynchronizer _fenceSynchronizer;
|
private readonly IFenceSynchronizer _fenceSynchronizer;
|
||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
@@ -601,6 +607,8 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
|
|
||||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public D3D12ResourceAllocator(
|
public D3D12ResourceAllocator(
|
||||||
IFenceSynchronizer fenceSynchronizer,
|
IFenceSynchronizer fenceSynchronizer,
|
||||||
D3D12RenderDevice device,
|
D3D12RenderDevice device,
|
||||||
@@ -610,14 +618,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
{
|
{
|
||||||
var desc = new D3D12MA_ALLOCATOR_DESC
|
var desc = new D3D12MA_ALLOCATOR_DESC
|
||||||
{
|
{
|
||||||
pAdapter = (IDXGIAdapter*)device.Adapter,
|
pAdapter = (IDXGIAdapter*)device.Adapter.Get(),
|
||||||
pDevice = (ID3D12Device*)device.NativeDevice,
|
pDevice = (ID3D12Device*)device.NativeDevice.Get(),
|
||||||
Flags = D3D12MA_ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA_ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED,
|
Flags = D3D12MA_ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA_ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED,
|
||||||
};
|
};
|
||||||
|
|
||||||
D3D12MA_Allocator* pAllocator = default;
|
D3D12MA_Allocator* pAllocator = default;
|
||||||
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
ThrowIfFailed(D3D12MA_CreateAllocator(&desc, &pAllocator));
|
||||||
nativeObject.Attach(pAllocator);
|
_d3d12MA.Attach(pAllocator);
|
||||||
|
|
||||||
_fenceSynchronizer = fenceSynchronizer;
|
_fenceSynchronizer = fenceSynchronizer;
|
||||||
_device = device;
|
_device = device;
|
||||||
@@ -648,7 +656,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
|
|
||||||
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
|
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
CheckTexture2DSize(desc.Width, desc.Height);
|
CheckTexture2DSize(desc.Width, desc.Height);
|
||||||
|
|
||||||
@@ -706,7 +714,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var initialState = DetermineInitialTextureState(desc.Usage);
|
var initialState = DetermineInitialTextureState(desc.Usage);
|
||||||
|
|
||||||
D3D12MA_Allocation* pAllocation = default;
|
D3D12MA_Allocation* pAllocation = default;
|
||||||
ThrowIfFailed(nativeObject.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
||||||
|
|
||||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||||
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
||||||
@@ -717,7 +725,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
|
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
|
||||||
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
|
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
|
||||||
|
|
||||||
_device.NativeDevice->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(TextureUsage.RenderTarget))
|
if (desc.Usage.HasFlag(TextureUsage.RenderTarget))
|
||||||
@@ -726,7 +734,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.rtv);
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.rtv);
|
||||||
var rtvDesc = CreateRtvDesc(pAllocation->GetResource());
|
var rtvDesc = CreateRtvDesc(pAllocation->GetResource());
|
||||||
|
|
||||||
_device.NativeDevice->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(TextureUsage.DepthStencil))
|
if (desc.Usage.HasFlag(TextureUsage.DepthStencil))
|
||||||
@@ -735,7 +743,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv);
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv);
|
||||||
var dsvDesc = CreateDsvDesc(pAllocation->GetResource());
|
var dsvDesc = CreateDsvDesc(pAllocation->GetResource());
|
||||||
|
|
||||||
_device.NativeDevice->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
||||||
@@ -744,7 +752,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
||||||
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
||||||
|
|
||||||
_device.NativeDevice->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
|
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
|
||||||
@@ -754,24 +762,27 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
|
|
||||||
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool isTemp = false)
|
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool isTemp = false)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var textureDesc = desc.ToTextureDescripton();
|
var textureDesc = desc.ToTextureDescripton();
|
||||||
return CreateTexture(ref textureDesc, isTemp);
|
return CreateTexture(in textureDesc, isTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
|
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
CheckBufferSize(desc.Size);
|
CheckBufferSize(desc.Size);
|
||||||
|
|
||||||
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage));
|
var alignedSize = desc.Size;
|
||||||
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
|
if (desc.Usage.HasFlag(BufferUsage.Constant))
|
||||||
if (isRaw)
|
|
||||||
{
|
{
|
||||||
resourceDescription.Format = DXGI_FORMAT_R32_TYPELESS;
|
// D3D12 CBV size must be 256-byte aligned
|
||||||
|
alignedSize = (uint)(desc.Size + 255) & ~255u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(alignedSize, ConvertBufferUsage(desc.Usage));
|
||||||
|
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
|
||||||
|
|
||||||
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
||||||
{
|
{
|
||||||
HeapType = ConvertMemoryType(desc.MemoryType),
|
HeapType = ConvertMemoryType(desc.MemoryType),
|
||||||
@@ -781,42 +792,41 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
var initialState = DetermineInitialBufferState(desc.Usage, desc.MemoryType);
|
var initialState = DetermineInitialBufferState(desc.Usage, desc.MemoryType);
|
||||||
|
|
||||||
D3D12MA_Allocation* pAllocation = default;
|
D3D12MA_Allocation* pAllocation = default;
|
||||||
ThrowIfFailed(nativeObject.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
var iid = IID.IID_NULL;
|
||||||
|
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, &iid, null));
|
||||||
|
|
||||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||||
var pResource = pAllocation->GetResource();
|
var pResource = pAllocation->GetResource();
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(BufferUsage.Constant))
|
if (desc.Usage.HasFlag(BufferUsage.Constant))
|
||||||
{
|
{
|
||||||
// D3D12 CBV size must be 256-byte aligned
|
|
||||||
var alignedSize = (uint)(desc.Size + 255) & ~255u;
|
|
||||||
|
|
||||||
resourceDescriptor.cbv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
resourceDescriptor.cbv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||||
|
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.cbv);
|
||||||
var cbvDesc = new D3D12_CONSTANT_BUFFER_VIEW_DESC
|
var cbvDesc = new D3D12_CONSTANT_BUFFER_VIEW_DESC
|
||||||
{
|
{
|
||||||
BufferLocation = pResource->GetGPUVirtualAddress(),
|
BufferLocation = pResource->GetGPUVirtualAddress(),
|
||||||
SizeInBytes = alignedSize
|
SizeInBytes = (uint)alignedSize
|
||||||
};
|
};
|
||||||
|
|
||||||
_device.NativeDevice->CreateConstantBufferView(&cbvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.cbv));
|
_device.NativeDevice.Get()->CreateConstantBufferView(&cbvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
|
if (desc.Usage.HasFlag(BufferUsage.ShaderResource))
|
||||||
{
|
{
|
||||||
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv);
|
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.srv);
|
||||||
var srvDesc = CreateBufferSrvDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
var srvDesc = CreateBufferSrvDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
||||||
|
|
||||||
_device.NativeDevice->CreateShaderResourceView(pResource, &srvDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateShaderResourceView(pResource, &srvDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.Usage.HasFlag(BufferUsage.UnorderedAccess))
|
if (desc.Usage.HasFlag(BufferUsage.UnorderedAccess))
|
||||||
{
|
{
|
||||||
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav);
|
||||||
var uavDesc = CreateBufferUavDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
var uavDesc = CreateBufferUavDesc(pAllocation->GetResource(), desc.Stride, isRaw);
|
||||||
|
|
||||||
_device.NativeDevice->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
|
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
|
||||||
@@ -825,7 +835,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
|
|
||||||
public Handle<GraphicsBuffer> CreateUploadBuffer(ulong size, bool isTemp = true)
|
public Handle<GraphicsBuffer> CreateUploadBuffer(ulong size, bool isTemp = true)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var desc = new BufferDesc
|
var desc = new BufferDesc
|
||||||
{
|
{
|
||||||
@@ -834,18 +844,18 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
MemoryType = ResourceMemoryType.Upload,
|
MemoryType = ResourceMemoryType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
return CreateBuffer(ref desc, isTemp);
|
return CreateBuffer(in desc, isTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var vertexBufferDesc = new BufferDesc
|
var vertexBufferDesc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = (uint)(vertices.Count * Unsafe.SizeOf<Vertex>()),
|
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
||||||
Stride = (uint)Unsafe.SizeOf<Vertex>(),
|
Stride = (uint)sizeof(Vertex),
|
||||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
MemoryType = ResourceMemoryType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -853,37 +863,47 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
{
|
{
|
||||||
Size = (uint)(indices.Count * sizeof(uint)),
|
Size = (uint)(indices.Count * sizeof(uint)),
|
||||||
Stride = sizeof(uint),
|
Stride = sizeof(uint),
|
||||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
MemoryType = ResourceMemoryType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var vertexBuffer = CreateBuffer(ref vertexBufferDesc);
|
var objectBufferDesc = new BufferDesc
|
||||||
var indexBuffer = CreateBuffer(ref indexBufferDesc);
|
{
|
||||||
|
Size = (uint)sizeof(PerObjectData),
|
||||||
|
Stride = (uint)sizeof(PerObjectData),
|
||||||
|
Usage = BufferUsage.Constant,
|
||||||
|
MemoryType = ResourceMemoryType.Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
var vertexBuffer = CreateBuffer(in vertexBufferDesc);
|
||||||
|
var indexBuffer = CreateBuffer(in indexBufferDesc);
|
||||||
|
var objectBuffer = CreateBuffer(in objectBufferDesc);
|
||||||
|
|
||||||
var data = new Mesh
|
var data = new Mesh
|
||||||
{
|
{
|
||||||
vertices = vertices,
|
Vertices = vertices,
|
||||||
indices = indices,
|
Indices = indices,
|
||||||
vertexBuffer = vertexBuffer,
|
VertexBuffer = vertexBuffer,
|
||||||
indexBuffer = indexBuffer,
|
IndexBuffer = indexBuffer,
|
||||||
|
ObjectDataBuffer = objectBuffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
return _resourceDatabase.AddMesh(ref data);
|
return _resourceDatabase.AddMesh(in data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Material> CreateMaterial(Identifier<Shader> shader)
|
public Handle<Material> CreateMaterial(Identifier<Shader> shader)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var material = new Material();
|
var material = new Material();
|
||||||
material.SetShader(shader, this, _resourceDatabase);
|
material.SetShader(shader, this, _resourceDatabase);
|
||||||
|
|
||||||
return _resourceDatabase.AddMaterial(ref material);
|
return _resourceDatabase.AddMaterial(in material);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor)
|
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var shader = new Shader(descriptor);
|
var shader = new Shader(descriptor);
|
||||||
foreach (var pass in descriptor.passes)
|
foreach (var pass in descriptor.passes)
|
||||||
@@ -893,6 +913,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Cache the pass key because we hash it multiple times right now.
|
||||||
var passKey = new ShaderPassKey(fullPass.Identifier);
|
var passKey = new ShaderPassKey(fullPass.Identifier);
|
||||||
var cbr = _pipelineLibrary.GetCBufferInfo(passKey);
|
var cbr = _pipelineLibrary.GetCBufferInfo(passKey);
|
||||||
if (cbr.Status != ResultStatus.Success)
|
if (cbr.Status != ResultStatus.Success)
|
||||||
@@ -908,7 +929,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
|
|
||||||
public void ReleaseTempResources()
|
public void ReleaseTempResources()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
while (_temResources.Count > 0)
|
while (_temResources.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -933,9 +954,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -952,8 +973,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject<D3D
|
|||||||
_resourceDatabase.ReleaseResource(handle);
|
_resourceDatabase.ReleaseResource(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d3d12MA.Dispose();
|
||||||
_temResources.Dispose();
|
_temResources.Dispose();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ using Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
internal class D3D12ResourceDatabase : IResourceDatabase
|
||||||
{
|
{
|
||||||
internal unsafe struct ResourceRecord
|
internal unsafe struct ResourceRecord
|
||||||
{
|
{
|
||||||
@@ -56,12 +55,12 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
this.desc = desc;
|
this.desc = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceRecord(ID3D12Resource* resource, ResourceState state)
|
public ResourceRecord(ID3D12Resource* resource, ResourceState state, ResourceViewGroup viewGroup)
|
||||||
{
|
{
|
||||||
this.resourceUnion = new ResourceUnion(resource);
|
this.resourceUnion = new ResourceUnion(resource);
|
||||||
this.isExternal = true;
|
this.isExternal = true;
|
||||||
|
|
||||||
this.viewGroup = default;
|
this.viewGroup = viewGroup;
|
||||||
this.cpuFenceValue = ~0u;
|
this.cpuFenceValue = ~0u;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.desc = ResourceDesc.FromD3D12(resource->GetDesc());
|
this.desc = ResourceDesc.FromD3D12(resource->GetDesc());
|
||||||
@@ -80,13 +79,13 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
{
|
{
|
||||||
refCount = resourceUnion.allocation.Get()->Release();
|
refCount = resourceUnion.allocation.Get()->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceUnion = default;
|
|
||||||
viewGroup = default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptorAllocator.Release(viewGroup);
|
descriptorAllocator.Release(viewGroup);
|
||||||
|
|
||||||
|
resourceUnion = default;
|
||||||
|
viewGroup = default;
|
||||||
|
|
||||||
return refCount;
|
return refCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,15 +106,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
|
|
||||||
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
||||||
{
|
{
|
||||||
_resources = new(64, Allocator.Persistent, AllocationOption.Clear);
|
_resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear);
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
_resourceName = new(64);
|
_resourceName = new Dictionary<Handle<GPUResource>, string>(64);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_meshes = new(64, Allocator.Persistent, AllocationOption.Clear);
|
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear);
|
||||||
_materials = new(16, Allocator.Persistent, AllocationOption.Clear);
|
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear);
|
||||||
_shaders = new(16);
|
_shaders = new DynamicArray<Shader?>(16);
|
||||||
_shaderPasses = new(16);
|
_shaderPasses = new Dictionary<ShaderPassKey, ShaderPass>(16);
|
||||||
|
|
||||||
_descriptorAllocator = descriptorAllocator;
|
_descriptorAllocator = descriptorAllocator;
|
||||||
}
|
}
|
||||||
@@ -132,11 +131,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
resource = default!;
|
resource = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, string? name = null)
|
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var id = _resources.Add(new ResourceRecord(pResource, initialState), out var generation);
|
var id = _resources.Add(new ResourceRecord(pResource, initialState, viewGroup), out var generation);
|
||||||
var handle = new Handle<GPUResource>(id, generation);
|
var handle = new Handle<GPUResource>(id, generation);
|
||||||
|
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
@@ -172,7 +171,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
return _resources.Contains(handle.id, handle.generation);
|
return _resources.Contains(handle.id, handle.generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref ResourceRecord GetResourceInfo(Handle<GPUResource> handle)
|
public ref ResourceRecord GetResourceRecord(Handle<GPUResource> handle)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -191,11 +190,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe ID3D12Resource* GetResource(Handle<GPUResource> handle)
|
public unsafe SharedPtr<ID3D12Resource> GetResource(Handle<GPUResource> handle)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
ref var info = ref GetResourceInfo(handle);
|
ref var info = ref GetResourceRecord(handle);
|
||||||
if (!info.Allocated)
|
if (!info.Allocated)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -207,7 +206,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
public ResourceState GetResourceState(Handle<GPUResource> handle)
|
public ResourceState GetResourceState(Handle<GPUResource> handle)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
return GetResourceInfo(handle).state;
|
return GetResourceRecord(handle).state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResourceState(Handle<GPUResource> handle, ResourceState state)
|
public void SetResourceState(Handle<GPUResource> handle, ResourceState state)
|
||||||
@@ -226,7 +225,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
public ResourceDesc GetResourceDescription(Handle<GPUResource> handle)
|
public ResourceDesc GetResourceDescription(Handle<GPUResource> handle)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
return GetResourceInfo(handle).desc;
|
return GetResourceRecord(handle).desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetBindlessIndex(Handle<GPUResource> handle)
|
public int GetBindlessIndex(Handle<GPUResource> handle)
|
||||||
@@ -273,10 +272,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
var refCount = info.Release(_descriptorAllocator);
|
var refCount = info.Release(_descriptorAllocator);
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
_resourceName.Remove(handle, out var name);
|
_resourceName.Remove(handle, out var name);
|
||||||
if (refCount > 0)
|
//if (refCount > 0)
|
||||||
{
|
//{
|
||||||
throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
|
// throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
|
||||||
}
|
//}
|
||||||
|
//Debug.Assert(refCount == 0, "Resource released with non-zero reference count.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_resources.Remove(handle.id, handle.generation);
|
_resources.Remove(handle.id, handle.generation);
|
||||||
@@ -435,10 +435,9 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
[Conditional("DEBUG"), Conditional("GHOST_EDITOR")]
|
|
||||||
static void ThrowMemoryLeakException(string resourceType, int count)
|
static void ThrowMemoryLeakException(string resourceType, int count)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing.");
|
throw new MemoryLeakException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.Contracts;
|
using Ghost.Graphics.Contracts;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -17,12 +18,19 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// D3D12 implementation of swap chain interface
|
/// D3D12 implementation of swap chain interface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapChain
|
internal unsafe class D3D12SwapChain : ISwapChain
|
||||||
{
|
{
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||||
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
|
private readonly D3D12RenderDevice _renderDevice;
|
||||||
|
|
||||||
|
private UniquePtr<IDXGISwapChain4> _swapChain;
|
||||||
private UnsafeArray<Handle<Texture>> _backBuffers;
|
private UnsafeArray<Handle<Texture>> _backBuffers;
|
||||||
|
|
||||||
|
private object? _compositionSurface;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public uint Width
|
public uint Width
|
||||||
{
|
{
|
||||||
get; private set;
|
get; private set;
|
||||||
@@ -38,9 +46,11 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, IDXGIFactory7* pFactory, ID3D12CommandQueue* pCommandQueue, SwapChainDesc desc)
|
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
|
||||||
{
|
{
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
_descriptorAllocator = descriptorAllocator;
|
||||||
|
_renderDevice = device;
|
||||||
|
|
||||||
_backBuffers = new UnsafeArray<Handle<Texture>>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
|
_backBuffers = new UnsafeArray<Handle<Texture>>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
|
||||||
|
|
||||||
@@ -48,11 +58,18 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
Height = desc.height;
|
Height = desc.height;
|
||||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
|
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
|
||||||
|
|
||||||
CreateSwapChain(pFactory, pCommandQueue, desc);
|
CreateSwapChain(desc);
|
||||||
CreateBackBuffers();
|
CreateBackBuffers();
|
||||||
|
|
||||||
|
_compositionSurface = desc.target.compositionSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSwapChain(IDXGIFactory7* pFactory, ID3D12CommandQueue* commandQueue, SwapChainDesc desc)
|
~D3D12SwapChain()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSwapChain(SwapChainDesc desc)
|
||||||
{
|
{
|
||||||
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
||||||
{
|
{
|
||||||
@@ -71,10 +88,13 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
|
|
||||||
IDXGISwapChain1* pTempSwapChain = default;
|
IDXGISwapChain1* pTempSwapChain = default;
|
||||||
|
|
||||||
|
var pFactory = _renderDevice.DXGIFactory.Get();
|
||||||
|
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
|
||||||
|
|
||||||
switch (desc.target.type)
|
switch (desc.target.type)
|
||||||
{
|
{
|
||||||
case SwapChainTargetType.Composition:
|
case SwapChainTargetType.Composition:
|
||||||
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)commandQueue, &swapChainDesc, null, &pTempSwapChain));
|
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
|
||||||
|
|
||||||
// Set the composition surface
|
// Set the composition surface
|
||||||
if (desc.target.compositionSurface != null)
|
if (desc.target.compositionSurface != null)
|
||||||
@@ -91,7 +111,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
};
|
};
|
||||||
|
|
||||||
pFactory->CreateSwapChainForHwnd(
|
pFactory->CreateSwapChainForHwnd(
|
||||||
(IUnknown*)commandQueue,
|
(IUnknown*)pCommandQueue,
|
||||||
new HWND(desc.target.windowHandle.ToPointer()),
|
new HWND(desc.target.windowHandle.ToPointer()),
|
||||||
&swapChainDesc,
|
&swapChainDesc,
|
||||||
&swapChainFullscreenDesc,
|
&swapChainFullscreenDesc,
|
||||||
@@ -107,7 +127,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
pTempSwapChain->QueryInterface(__uuidof(pSwapChain), (void**)&pSwapChain);
|
pTempSwapChain->QueryInterface(__uuidof(pSwapChain), (void**)&pSwapChain);
|
||||||
pTempSwapChain->Release();
|
pTempSwapChain->Release();
|
||||||
|
|
||||||
nativeObject.Attach(pSwapChain);
|
_swapChain.Attach(pSwapChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateBackBuffers()
|
private void CreateBackBuffers()
|
||||||
@@ -115,33 +135,37 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
for (uint i = 0; i < BufferCount; i++)
|
for (uint i = 0; i < BufferCount; i++)
|
||||||
{
|
{
|
||||||
ID3D12Resource* pBackBuffer = default;
|
ID3D12Resource* pBackBuffer = default;
|
||||||
nativeObject.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer);
|
ThrowIfFailed(_swapChain.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer));
|
||||||
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
|
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
|
||||||
|
|
||||||
_backBuffers[i] = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present).AsTexture();
|
var rtv = _descriptorAllocator.AllocateRTV();
|
||||||
|
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
|
||||||
|
|
||||||
|
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, new ResourceViewGroup() { rtv = rtv });
|
||||||
|
_backBuffers[i] = handle.AsTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Handle<Texture> GetCurrentBackBuffer()
|
public Handle<Texture> GetCurrentBackBuffer()
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
return _backBuffers[nativeObject.Get()->GetCurrentBackBufferIndex()];
|
return _backBuffers[_swapChain.Get()->GetCurrentBackBufferIndex()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Present(bool vsync = true)
|
public void Present(bool vsync = true)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var presentFlags = 0u;
|
var presentFlags = 0u;
|
||||||
var syncInterval = vsync ? 1u : 0u;
|
var syncInterval = vsync ? 1u : 0u;
|
||||||
|
|
||||||
ThrowIfFailed(nativeObject.Get()->Present(syncInterval, presentFlags));
|
ThrowIfFailed(_swapChain.Get()->Present(syncInterval, presentFlags));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Resize(uint width, uint height)
|
public void Resize(uint width, uint height)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (Width == width && Height == height)
|
if (Width == width && Height == height)
|
||||||
{
|
{
|
||||||
@@ -155,7 +179,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resize the swap chain
|
// Resize the swap chain
|
||||||
if (nativeObject.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED)
|
if (_swapChain.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to resize swap chain buffers.");
|
throw new InvalidOperationException("Failed to resize swap chain buffers.");
|
||||||
}
|
}
|
||||||
@@ -167,20 +191,28 @@ internal unsafe class D3D12SwapChain : IUnknownObject<IDXGISwapChain4>, ISwapCha
|
|||||||
CreateBackBuffers();
|
CreateBackBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_compositionSurface != null)
|
||||||
|
{
|
||||||
|
using var panelNative = ISwapChainPanelNative.FromSwapChainPanel(_compositionSurface);
|
||||||
|
panelNative.SetSwapChain(IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < _backBuffers.Count; i++)
|
for (var i = 0; i < _backBuffers.Count; i++)
|
||||||
{
|
{
|
||||||
_resourceDatabase.ReleaseResource(_backBuffers[i].AsResource());
|
_resourceDatabase.ReleaseResource(_backBuffers[i].AsResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
_backBuffers.Dispose();
|
_backBuffers.Dispose();
|
||||||
|
_swapChain.Dispose();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
HeapType = type;
|
HeapType = type;
|
||||||
NumDescriptors = numDescriptors;
|
NumDescriptors = numDescriptors;
|
||||||
ShaderVisible = type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
ShaderVisible = type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||||
Stride = device.NativeDevice->GetDescriptorHandleIncrementSize(type);
|
Stride = device.NativeDevice.Get()->GetDescriptorHandleIncrementSize(type);
|
||||||
|
|
||||||
_dynamicHeapStart = Math.Clamp(dynamicHeapStart, 0, numDescriptors);
|
_dynamicHeapStart = Math.Clamp(dynamicHeapStart, 0, numDescriptors);
|
||||||
_currentDynamicOffset = 0;
|
_currentDynamicOffset = 0;
|
||||||
@@ -254,14 +254,14 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newLocation = AllocateDescriptors(count);
|
var newLocation = AllocateDescriptors(count);
|
||||||
_device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType);
|
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType);
|
||||||
|
|
||||||
return newLocation;
|
return newLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
|
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
|
||||||
{
|
{
|
||||||
_device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AllocateResources(int numDescriptors)
|
private bool AllocateResources(int numDescriptors)
|
||||||
@@ -279,7 +279,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
};
|
};
|
||||||
|
|
||||||
ID3D12DescriptorHeap* pHeap = default;
|
ID3D12DescriptorHeap* pHeap = default;
|
||||||
var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap);
|
var hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap);
|
||||||
if (hr.FAILED)
|
if (hr.FAILED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -291,11 +291,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
|
|
||||||
if (!_allocatedDescriptors.IsCreated)
|
if (!_allocatedDescriptors.IsCreated)
|
||||||
{
|
{
|
||||||
_allocatedDescriptors = new UnsafeArray<bool>(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
_allocatedDescriptors = new UnsafeArray<bool>(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_allocatedDescriptors.Resize(numDescriptors);
|
_allocatedDescriptors.Resize(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShaderVisible)
|
if (ShaderVisible)
|
||||||
@@ -303,7 +303,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
ID3D12DescriptorHeap* pShaderVisibleHeap = default;
|
ID3D12DescriptorHeap* pShaderVisibleHeap = default;
|
||||||
|
|
||||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||||
hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap);
|
hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap);
|
||||||
if (hr.FAILED)
|
if (hr.FAILED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -332,11 +332,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||||
|
|
||||||
if (_shaderVisibleHeap.Get() != null)
|
if (_shaderVisibleHeap.Get() != null)
|
||||||
{
|
{
|
||||||
_device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -350,12 +350,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
Debug.Assert(NumAllocatedDescriptors == 0);
|
||||||
if (NumAllocatedDescriptors > 0)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"Warning: Descriptor heap of type {HeapType} is being disposed with {NumAllocatedDescriptors} allocated descriptors.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_heap.Dispose();
|
_heap.Dispose();
|
||||||
_shaderVisibleHeap.Dispose();
|
_shaderVisibleHeap.Dispose();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Misaki.HighPerformance.LowLevel;
|
||||||
|
|
||||||
namespace Ghost.Graphics;
|
namespace Ghost.Graphics;
|
||||||
|
|
||||||
internal unsafe class GPUResourceLeakException : Exception
|
internal unsafe class GPUResourceLeakException : Exception
|
||||||
@@ -6,4 +8,12 @@ internal unsafe class GPUResourceLeakException : Exception
|
|||||||
: base($"GPU resource leak detected! Resource '{name}' at address {(UIntPtr)address} has a reference count of {refCount} when it should be 0. This indicates that the resource was not properly released before being destroyed, which can lead to memory leaks and other issues. Please ensure that all references to this resource are released appropriately.")
|
: base($"GPU resource leak detected! Resource '{name}' at address {(UIntPtr)address} has a reference count of {refCount} when it should be 0. This indicates that the resource was not properly released before being destroyed, which can lead to memory leaks and other issues. Please ensure that all references to this resource are released appropriately.")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ThrowIfRefCountNonZero(uint refCount, void* address, string name)
|
||||||
|
{
|
||||||
|
if (refCount != 0)
|
||||||
|
{
|
||||||
|
throw new GPUResourceLeakException(refCount, address, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ public ref struct GraphicsPSODescriptor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct CBufferPropertyInfo
|
public readonly struct CBufferPropertyInfo
|
||||||
{
|
{
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
@@ -184,7 +184,7 @@ public readonly record struct CBufferPropertyInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct CBufferInfo
|
public readonly struct CBufferInfo
|
||||||
{
|
{
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ public interface ICommandBuffer : IDisposable
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the command buffer.
|
|
||||||
/// </summary>
|
|
||||||
string Name
|
string Name
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public interface IShaderPipeline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IPipelineLibrary
|
public interface IPipelineLibrary : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load pipeline library from disk.
|
/// Load pipeline library from disk.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Ghost.Graphics.Core;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
public interface IResourceAllocator
|
public interface IResourceAllocator : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a texture resource
|
/// Creates a texture resource
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public interface IResourceReleasable
|
|||||||
void ReleaseResource(IResourceDatabase database);
|
void ReleaseResource(IResourceDatabase database);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IResourceDatabase
|
public interface IResourceDatabase : IDisposable
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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 Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Utilities;
|
using Misaki.HighPerformance.Utilities;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
@@ -57,42 +58,40 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
ctx.PipelineLibrary.CompilePSO(in psoDes, in compileResult.GetValueRef()).GetValueOrThrow();
|
ctx.PipelineLibrary.CompilePSO(in psoDes, in compileResult.GetValueRef()).GetValueOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices);
|
MeshBuilder.CreateCube(0.75f, default, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, out var vertices, out var indices);
|
||||||
|
|
||||||
_mesh = ctx.CreateMesh(vertices, indices);
|
_mesh = ctx.CreateMesh(vertices, indices);
|
||||||
|
ctx.UpdateObjectData(_mesh, float4x4.identity);
|
||||||
ctx.UploadMesh(_mesh, true);
|
ctx.UploadMesh(_mesh, true);
|
||||||
|
|
||||||
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
|
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
|
||||||
_material = ctx.ResourceAllocator.CreateMaterial(_shader);
|
_material = ctx.ResourceAllocator.CreateMaterial(_shader);
|
||||||
|
|
||||||
var imageResults = new ImageResult[_textureFiles.Length];
|
//_textures = new Handle<Texture>[_textureFiles.Length];
|
||||||
|
//for (var i = 0; i < _textureFiles.Length; i++)
|
||||||
|
//{
|
||||||
|
// using var stream = File.OpenRead(_textureFiles[i]);
|
||||||
|
// using var imageData = ImageResult.FromStream(stream);
|
||||||
|
|
||||||
_textures = new Handle<Texture>[_textureFiles.Length];
|
// var desc = new TextureDesc
|
||||||
for (var i = 0; i < _textureFiles.Length; i++)
|
// {
|
||||||
{
|
// Width = imageData.Width,
|
||||||
using var stream = File.OpenRead(_textureFiles[i]);
|
// Height = imageData.Height,
|
||||||
using var imageData = ImageResult.FromStream(stream);
|
// Dimension = TextureDimension.Texture2D,
|
||||||
imageResults[i] = imageData;
|
// Format = TextureFormat.R8G8B8A8_UNorm,
|
||||||
|
// MipLevels = 1,
|
||||||
|
// Slice = 1,
|
||||||
|
// Usage = TextureUsage.ShaderResource,
|
||||||
|
// };
|
||||||
|
|
||||||
var desc = new TextureDesc
|
// _textures[i] = ctx.CreateTexture(ref desc);
|
||||||
{
|
// ctx.UploadTexture(_textures[i], new Span<byte>(imageData.Data, (int)imageData.Size));
|
||||||
Width = imageData.Width,
|
//}
|
||||||
Height = imageData.Height,
|
|
||||||
Dimension = TextureDimension.Texture2D,
|
|
||||||
Format = TextureFormat.R8G8B8A8_UNorm,
|
|
||||||
MipLevels = 1,
|
|
||||||
Slice = 1,
|
|
||||||
Usage = TextureUsage.ShaderResource,
|
|
||||||
};
|
|
||||||
|
|
||||||
_textures[i] = ctx.CreateTexture(ref desc);
|
|
||||||
ctx.UploadTexture(_textures[i], new Span<byte>(imageData.Data, (int)imageData.Size));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(ref readonly RenderingContext ctx)
|
public void Execute(ref readonly RenderingContext ctx)
|
||||||
{
|
{
|
||||||
ctx.DispatchMesh(_mesh, _material, "Forward", 8);
|
ctx.DispatchMesh(_mesh, _material, "Forward", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup(IResourceDatabase resourceDatabase)
|
public void Cleanup(IResourceDatabase resourceDatabase)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ void MSMain(
|
|||||||
out vertices PixelInput outVerts[3],
|
out vertices PixelInput outVerts[3],
|
||||||
out indices uint3 outTris[1])
|
out indices uint3 outTris[1])
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
// Fetch bindless buffers
|
// Fetch bindless buffers
|
||||||
ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerObjectData.vertexBuffer];
|
ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerObjectData.vertexBuffer];
|
||||||
ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerObjectData.indexBuffer];
|
ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerObjectData.indexBuffer];
|
||||||
@@ -45,8 +46,7 @@ void MSMain(
|
|||||||
v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 64));
|
v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 64));
|
||||||
|
|
||||||
SetMeshOutputCounts(3, 1);
|
SetMeshOutputCounts(3, 1);
|
||||||
|
//v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
|
||||||
v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
|
|
||||||
|
|
||||||
// Write vertex output
|
// Write vertex output
|
||||||
outVerts[vertexId].position = v.position;
|
outVerts[vertexId].position = v.position;
|
||||||
@@ -58,15 +58,50 @@ void MSMain(
|
|||||||
{
|
{
|
||||||
outTris[0] = uint3(0, 1, 2);
|
outTris[0] = uint3(0, 1, 2);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// 1. Tell the hardware how much data to expect
|
||||||
|
SetMeshOutputCounts(3, 1);
|
||||||
|
|
||||||
|
// 2. Hardcoded Clip Space Positions (X, Y, Z, W)
|
||||||
|
// Visible range: X[-1, 1], Y[-1, 1], Z[0, 1]
|
||||||
|
// W must be 1.0
|
||||||
|
float4 positions[3] =
|
||||||
|
{
|
||||||
|
float4(0.0f, 0.5f, 0.5f, 1.0f), // Top
|
||||||
|
float4(0.5f, -0.5f, 0.5f, 1.0f), // Bottom Right
|
||||||
|
float4(-0.5f, -0.5f, 0.5f, 1.0f) // Bottom Left
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 colors[3] =
|
||||||
|
{
|
||||||
|
float4(g_PerObjectData.vertexBuffer, 0.0f, 0.0f, 1.0f), // Red
|
||||||
|
float4(0.0f, g_PerObjectData.indexBuffer, 0.0f, 1.0f), // Green
|
||||||
|
float4(0.0f, 0.0f, 0.0f, 1.0f) // Blue
|
||||||
|
};
|
||||||
|
|
||||||
|
uint gtid = groupThreadID.x;
|
||||||
|
|
||||||
|
// 3. Write Vertex Data (Parallel)
|
||||||
|
outVerts[gtid].position = positions[gtid];
|
||||||
|
outVerts[gtid].color = colors[gtid];
|
||||||
|
|
||||||
|
// 4. Write Index Data (Only 1st thread needs to do this)
|
||||||
|
if (gtid == 0)
|
||||||
|
{
|
||||||
|
// Clockwise winding (Standard for DX12)
|
||||||
|
outTris[0] = uint3(0, 1, 2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 PSMain(PixelInput input) : SV_TARGET
|
float4 PSMain(PixelInput input) : SV_TARGET
|
||||||
{
|
{
|
||||||
float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy);
|
//float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy);
|
||||||
float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy);
|
//float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy);
|
||||||
float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy);
|
//float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy);
|
||||||
float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy);
|
//float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy);
|
||||||
|
|
||||||
float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
//float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
||||||
return blendedColor * g_PerMaterialData.color;
|
return g_PerMaterialData.color + input.color;;
|
||||||
|
//return input.color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,11 +172,7 @@ internal class RenderSystem : IRenderSystem
|
|||||||
|
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
_shutdownEvent.Set();
|
_shutdownEvent.Set();
|
||||||
|
_renderThread.Join();
|
||||||
if (_renderThread.IsAlive)
|
|
||||||
{
|
|
||||||
_renderThread.Join();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool WaitForGPUReady(int timeOut = -1)
|
public bool WaitForGPUReady(int timeOut = -1)
|
||||||
@@ -242,7 +238,10 @@ internal class RenderSystem : IRenderSystem
|
|||||||
frameResource.Dispose();
|
frameResource.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_graphicsEngine.Dispose();
|
||||||
_shutdownEvent.Dispose();
|
_shutdownEvent.Dispose();
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ internal sealed partial class DxcShaderCompiler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler, IDisposable
|
internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
||||||
{
|
{
|
||||||
private UniquePtr<IDxcCompiler3> _compiler;
|
private UniquePtr<IDxcCompiler3> _compiler;
|
||||||
private UniquePtr<IDxcUtils> _utils;
|
private UniquePtr<IDxcUtils> _utils;
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ public unsafe static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a unit cube centered at the origin with size 1.
|
/// Creates a unit cube centered at the origin with size 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void CreateCube(float size, Color128 color, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
public static void CreateCube(float size, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
||||||
{
|
{
|
||||||
var half = size * 0.5f;
|
var half = size * 0.5f;
|
||||||
|
|
||||||
vertices = new UnsafeList<Vertex>(24, Allocator.Persistent);
|
vertices = new UnsafeList<Vertex>(24, allocator);
|
||||||
indices = new UnsafeList<uint>(36, Allocator.Persistent);
|
indices = new UnsafeList<uint>(36, allocator);
|
||||||
|
|
||||||
var corners = new float4[]
|
var corners = new float4[]
|
||||||
{
|
{
|
||||||
@@ -71,13 +71,13 @@ public unsafe static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a plane on the XZ axis centered at the origin.
|
/// Creates a plane on the XZ axis centered at the origin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void CreatePlane(float width, float depth, Color128 color, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
public static void CreatePlane(float width, float depth, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
||||||
{
|
{
|
||||||
var hw = width * 0.5f;
|
var hw = width * 0.5f;
|
||||||
var hd = depth * 0.5f;
|
var hd = depth * 0.5f;
|
||||||
|
|
||||||
vertices = new UnsafeList<Vertex>(4, Allocator.Persistent);
|
vertices = new UnsafeList<Vertex>(4, allocator);
|
||||||
indices = new UnsafeList<uint>(6, Allocator.Persistent);
|
indices = new UnsafeList<uint>(6, allocator);
|
||||||
|
|
||||||
vertices.Add(new Vertex()
|
vertices.Add(new Vertex()
|
||||||
{
|
{
|
||||||
@@ -129,10 +129,10 @@ public unsafe static class MeshBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a UV sphere centered at the origin.
|
/// Creates a UV sphere centered at the origin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void CreateSphere(int latitudeSegments, int longitudeSegments, float radius, Color128 color, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
public static void CreateSphere(int latitudeSegments, int longitudeSegments, float radius, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
||||||
{
|
{
|
||||||
vertices = new UnsafeList<Vertex>((latitudeSegments + 1) * (longitudeSegments + 1), Allocator.Persistent);
|
vertices = new UnsafeList<Vertex>((latitudeSegments + 1) * (longitudeSegments + 1), allocator);
|
||||||
indices = new UnsafeList<uint>(latitudeSegments * longitudeSegments * 6, Allocator.Persistent);
|
indices = new UnsafeList<uint>(latitudeSegments * longitudeSegments * 6, allocator);
|
||||||
|
|
||||||
// Vertices
|
// Vertices
|
||||||
for (var lat = 0; lat <= latitudeSegments; lat++)
|
for (var lat = 0; lat <= latitudeSegments; lat++)
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ shader "MyShader/Standard"
|
|||||||
tex2d_b texture4 = tex2d_b(normal);
|
tex2d_b texture4 = tex2d_b(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline
|
|
||||||
{
|
|
||||||
ztest = less_equal;
|
|
||||||
zwrite = on;
|
|
||||||
cull = back;
|
|
||||||
blend = opaque;
|
|
||||||
color_mask = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass "Forward"
|
pass "Forward"
|
||||||
{
|
{
|
||||||
|
pipeline
|
||||||
|
{
|
||||||
|
ztest = disable;
|
||||||
|
zwrite = off;
|
||||||
|
cull = off;
|
||||||
|
blend = opaque;
|
||||||
|
color_mask = 15;
|
||||||
|
}
|
||||||
|
|
||||||
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
||||||
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ internal static class SDLCompiler
|
|||||||
var fullPass = new FullPassDescriptor
|
var fullPass = new FullPassDescriptor
|
||||||
{
|
{
|
||||||
uniqueIdentifier = GetPassUniqueId(semantics, pass),
|
uniqueIdentifier = GetPassUniqueId(semantics, pass),
|
||||||
|
name = pass.name,
|
||||||
taskShader = pass.taskShader,
|
taskShader = pass.taskShader,
|
||||||
meshShader = pass.meshShader,
|
meshShader = pass.meshShader,
|
||||||
pixelShader = pass.pixelShader,
|
pixelShader = pass.pixelShader,
|
||||||
|
|||||||
Reference in New Issue
Block a user