Refactor AppState and rendering pipeline components
Changed the `AppStateMachine` to implement `IDisposable` and `IAsyncDisposable` for better resource management. Changed the `IAppState` interface to include asynchronous methods for state transitions. Changed the `App` class to start the host asynchronously and added an `OnClosed` method for proper shutdown. Changed the `EditorState` class to ensure the window closes correctly when exiting the state. Changed the `LandingState` class to improve window activation and deactivation management. Changed the `HostHelper` class to register `LandingWindow` and `EngineEditorWindow` as singletons for better performance. Changed the `ScenePage` class to utilize a new interface for swap chain management. Changed the `OpenProjectPage` and `CreateProjectPage` classes to enhance navigation handling. Changed the `ConsoleViewModel` to improve log update handling with a new context structure. Changed the `OpenProjectViewModel` to clear project lists when navigating away. Changed the `EngineCore` class to start the graphics pipeline asynchronously. Changed the `Logger` class to use a new context structure for log changes. Added the `ICommandBuffer`, `IGraphicsDevice`, and `IRenderView` interfaces to enhance the rendering pipeline. Changed the `DX12CommandBuffer`, `DX12GraphicsDevice`, and `DX12RenderView` classes for improved resource management and rendering efficiency. Refactored the `Mesh` class to use a new `Vertex` structure for simplified vertex management. Added the `TextureUtility` class for texture management utilities, including mip count calculation. Changed the `launchSettings.json` to include a new profile for the graphics project with native debugging enabled. Changed the `MeshBuilder` class to utilize the new `Vertex` structure for vertex creation.
This commit is contained in:
@@ -10,7 +10,7 @@ internal class D3D12DescriptorAllocator : IDisposable
|
||||
private const DescriptorIndex _INVALID_DESCRIPTOR_INDEX = ~0u;
|
||||
|
||||
private readonly ID3D12Device _device;
|
||||
private readonly Lock _mutex = new();
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
private ID3D12DescriptorHeap? _heap;
|
||||
private ID3D12DescriptorHeap? _shaderVisibleHeap;
|
||||
@@ -56,14 +56,15 @@ internal class D3D12DescriptorAllocator : IDisposable
|
||||
ShaderVisible = type == DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView || type == DescriptorHeapType.Sampler;
|
||||
Stride = device.GetDescriptorHandleIncrementSize(type);
|
||||
|
||||
Debug.Assert(AllocateResources(numDescriptors));
|
||||
var success = AllocateResources(numDescriptors);
|
||||
Debug.Assert(success);
|
||||
}
|
||||
|
||||
public DescriptorIndex AllocateDescriptor() => AllocateDescriptors(1);
|
||||
|
||||
public DescriptorIndex AllocateDescriptors(uint count)
|
||||
{
|
||||
lock (_mutex)
|
||||
lock (_lock)
|
||||
{
|
||||
DescriptorIndex foundIndex = 0;
|
||||
uint freeCount = 0;
|
||||
@@ -120,7 +121,7 @@ internal class D3D12DescriptorAllocator : IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_mutex)
|
||||
lock (_lock)
|
||||
{
|
||||
for (var index = baseIndex; index < baseIndex + count; index++)
|
||||
{
|
||||
|
||||
679
Ghost.Graphics/DX12/Utilities/D3D12ResourceUploadBatch.cs
Normal file
679
Ghost.Graphics/DX12/Utilities/D3D12ResourceUploadBatch.cs
Normal file
File diff suppressed because one or more lines are too long
234
Ghost.Graphics/DX12/Utilities/D3D12ResourceUtils.cs
Normal file
234
Ghost.Graphics/DX12/Utilities/D3D12ResourceUtils.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using Ghost.Graphics.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Vortice.Direct3D12;
|
||||
using Vortice.DXGI;
|
||||
|
||||
namespace Ghost.Graphics.DX12.Utilities;
|
||||
|
||||
internal unsafe class D3D12ResourceUtils
|
||||
{
|
||||
private const ResourceStates _INITIALCOPYTARGETSTATE = ResourceStates.Common;
|
||||
private const ResourceStates _INITIALREADTARGETSTATE = ResourceStates.Common;
|
||||
private const ResourceStates _INITIALUAVTARGETSTATE = ResourceStates.Common;
|
||||
|
||||
public static ID3D12Resource CreateStaticBuffer<T>(
|
||||
ID3D12Device device,
|
||||
D3D12ResourceUploadBatch resourceUpload,
|
||||
T[] data, ResourceStates afterState,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
where T : unmanaged
|
||||
{
|
||||
Span<T> span = data;
|
||||
return CreateStaticBuffer(device, resourceUpload, span, afterState, flags);
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateStaticBuffer<T>(
|
||||
ID3D12Device device,
|
||||
D3D12ResourceUploadBatch resourceUpload,
|
||||
Span<T> data,
|
||||
ResourceStates afterState,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
where T : unmanaged
|
||||
{
|
||||
var sizeInBytes = (uint)(sizeof(T) * data.Length);
|
||||
|
||||
var c_maxBytes = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
|
||||
if (sizeInBytes > c_maxBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
|
||||
var buffer = device.CreateCommittedResource(
|
||||
HeapType.Default,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
_INITIALCOPYTARGETSTATE
|
||||
);
|
||||
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
SubresourceData initData = new()
|
||||
{
|
||||
pData = dataPtr,
|
||||
};
|
||||
|
||||
resourceUpload.Upload(buffer, 0, &initData, 1);
|
||||
resourceUpload.Transition(buffer, ResourceStates.CopyDest, afterState);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateUploadBuffer<T>(
|
||||
ID3D12Device device,
|
||||
T[] data,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
where T : unmanaged
|
||||
{
|
||||
var sizeInBytes = (uint)(sizeof(T) * data.Length);
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
return CreateUploadBuffer(device, sizeInBytes, dataPtr, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateUploadBuffer<T>(
|
||||
ID3D12Device device,
|
||||
Span<T> data,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
where T : unmanaged
|
||||
{
|
||||
var sizeInBytes = (uint)(sizeof(T) * data.Length);
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
return CreateUploadBuffer(device, sizeInBytes, dataPtr, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateUploadBuffer(
|
||||
ID3D12Device device,
|
||||
uint sizeInBytes,
|
||||
void* data = default,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
var c_maxBytes = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
|
||||
if (sizeInBytes > c_maxBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
|
||||
var buffer = device.CreateCommittedResource(
|
||||
HeapType.Upload,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
ResourceStates.GenericRead
|
||||
);
|
||||
|
||||
if (data is not null)
|
||||
{
|
||||
void* mappedPtr = default;
|
||||
buffer.Map(0, null, &mappedPtr).CheckError();
|
||||
Unsafe.CopyBlock(data, mappedPtr, sizeInBytes);
|
||||
buffer.Unmap(0, null);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateReadbackBuffer(
|
||||
ID3D12Device device,
|
||||
uint sizeInBytes,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
var c_maxBytes = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
if (sizeInBytes > c_maxBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
var buffer = device.CreateCommittedResource(
|
||||
HeapType.Readback,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
_INITIALREADTARGETSTATE
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateCPUDestinationBuffer(
|
||||
ID3D12Device device,
|
||||
uint sizeInBytes,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
var c_maxBytes = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
if (sizeInBytes > c_maxBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
|
||||
var buffer = device.CreateCommittedResource(
|
||||
HeapType.Default,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
ResourceStates.CopyDest
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateUAVBuffer(ID3D12Device device, uint bufferSize,
|
||||
ResourceStates initialState = ResourceStates.Common,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
var c_maxBytes = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
|
||||
if (bufferSize > c_maxBytes)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {bufferSize})");
|
||||
}
|
||||
|
||||
var buffer = device.CreateCommittedResource(
|
||||
HeapType.Default,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(bufferSize, ResourceFlags.AllowUnorderedAccess | flags),
|
||||
_INITIALCOPYTARGETSTATE
|
||||
);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static ID3D12Resource CreateTexture2D<T>(
|
||||
ID3D12Device device,
|
||||
D3D12ResourceUploadBatch resourceUpload,
|
||||
uint width, uint height, Format format,
|
||||
Span<T> data,
|
||||
bool generateMips = false,
|
||||
ResourceStates afterState = ResourceStates.PixelShaderResource,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
where T : unmanaged
|
||||
{
|
||||
if ((width > D3D12.RequestTexture2DUOrVDimension) || (height > D3D12.RequestTexture2DUOrVDimension))
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource dimensions too large for DirectX 12 (2D: size {width} by {height})");
|
||||
}
|
||||
|
||||
ushort mipLevels = 1;
|
||||
if (generateMips)
|
||||
{
|
||||
generateMips = resourceUpload.IsSupportedForGenerateMips(format);
|
||||
if (generateMips)
|
||||
{
|
||||
mipLevels = (ushort)TextureUtility.CountMips(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var texture = device.CreateCommittedResource(
|
||||
HeapType.Default,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Texture2D(format, width, height, 1, mipLevels, 1, 0, flags),
|
||||
_INITIALCOPYTARGETSTATE
|
||||
);
|
||||
|
||||
fixed (T* dataPtr = data)
|
||||
{
|
||||
FormatHelper.GetSurfaceInfo(format, width, height, out var rowPitch, out var slicePitch);
|
||||
SubresourceData initData = new()
|
||||
{
|
||||
pData = dataPtr,
|
||||
RowPitch = (nint)rowPitch,
|
||||
SlicePitch = (nint)slicePitch
|
||||
};
|
||||
|
||||
resourceUpload.Upload(texture, 0, &initData, 1);
|
||||
resourceUpload.Transition(texture, ResourceStates.CopyDest, afterState);
|
||||
|
||||
if (generateMips)
|
||||
{
|
||||
resourceUpload.GenerateMips(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user