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:
2025-11-26 01:48:24 +09:00
parent dfe786a2aa
commit 0720444c2c
40 changed files with 1008 additions and 903 deletions

View File

@@ -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" />

View File

@@ -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)
{ {

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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

View File

@@ -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" #>

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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);

View File

@@ -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]

View File

@@ -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;

View File

@@ -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);
}
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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;
};

View File

@@ -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;
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
} }
} }

View File

@@ -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);

View File

@@ -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);
} }
} }

View File

@@ -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)

View File

@@ -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);
} }
} }

View File

@@ -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();

View File

@@ -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);
}
}
} }

View File

@@ -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
{ {

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -11,7 +11,7 @@ public interface IResourceReleasable
void ReleaseResource(IResourceDatabase database); void ReleaseResource(IResourceDatabase database);
} }
public interface IResourceDatabase public interface IResourceDatabase : IDisposable
{ {
/* /*
/// <summary> /// <summary>

View File

@@ -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)

View File

@@ -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;
} }

View File

@@ -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);
} }
} }

View File

@@ -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;

View File

@@ -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++)

View File

@@ -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");
} }

View File

@@ -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,