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:
2025-06-29 11:38:29 +09:00
parent 4110c166cf
commit 8fd1222780
34 changed files with 1479 additions and 269 deletions

View File

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

File diff suppressed because one or more lines are too long

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