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:
14
Ghost.Graphics/DX12/DX12CommandBuffer.cs
Normal file
14
Ghost.Graphics/DX12/DX12CommandBuffer.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Vortice.Direct3D12;
|
||||
|
||||
namespace Ghost.Graphics.DX12;
|
||||
|
||||
internal class DX12CommandBuffer : ICommandBuffer
|
||||
{
|
||||
private ID3D12GraphicsCommandList10 _commandList;
|
||||
|
||||
public DX12CommandBuffer(ID3D12GraphicsCommandList10 commandList)
|
||||
{
|
||||
_commandList = commandList;
|
||||
}
|
||||
}
|
||||
@@ -8,29 +8,29 @@ namespace Ghost.Graphics.DX12;
|
||||
|
||||
internal class DX12DebugLayer : IDebugLayer
|
||||
{
|
||||
#if DEBUG
|
||||
private readonly ID3D12Debug6 _d3d12Debug;
|
||||
private readonly IDXGIDebug1 _dxgiDebug;
|
||||
#endif
|
||||
private readonly IDXGIInfoQueue? _dxgiInfoQueue;
|
||||
|
||||
public DX12DebugLayer()
|
||||
{
|
||||
#if DEBUG
|
||||
_d3d12Debug = D3D12.D3D12GetDebugInterface<ID3D12Debug6>();
|
||||
_d3d12Debug.EnableDebugLayer();
|
||||
|
||||
_dxgiDebug = DXGI.DXGIGetDebugInterface1<IDXGIDebug1>();
|
||||
_dxgiDebug.EnableLeakTrackingForThread();
|
||||
#endif
|
||||
|
||||
_dxgiInfoQueue = DXGI.DXGIGetDebugInterface1<IDXGIInfoQueue>();
|
||||
_dxgiInfoQueue.SetBreakOnSeverity(DXGI.DebugAll, InfoQueueMessageSeverity.Error, true);
|
||||
_dxgiInfoQueue.SetBreakOnSeverity(DXGI.DebugAll, InfoQueueMessageSeverity.Corruption, true);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
#if DEBUG
|
||||
_dxgiDebug.ReportLiveObjects(DXGI.DebugAll, ReportLiveObjectFlags.Detail | ReportLiveObjectFlags.IgnoreInternal);
|
||||
|
||||
_d3d12Debug?.Dispose();
|
||||
_dxgiDebug?.Dispose();
|
||||
#endif
|
||||
_d3d12Debug.Dispose();
|
||||
_dxgiDebug.Dispose();
|
||||
_dxgiInfoQueue?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,14 @@ internal class DX12GraphicsDevice : IGraphicsDevice
|
||||
private readonly ID3D12CommandQueue _commandQueue;
|
||||
|
||||
private readonly List<IRenderView> _renderViews = new();
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
#if DEBUG
|
||||
private readonly IDebugLayer _debugLayer;
|
||||
private readonly DX12DebugLayer _debugLayer;
|
||||
#endif
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public ID3D12Device14 Device => _device;
|
||||
public IDXGIFactory7 DXGIFactory => _dxgiFactory;
|
||||
public ID3D12CommandQueue CommandQueue => _commandQueue;
|
||||
@@ -61,6 +64,8 @@ internal class DX12GraphicsDevice : IGraphicsDevice
|
||||
adapter.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
adapter.Dispose();
|
||||
}
|
||||
|
||||
if (d3d12Device == null)
|
||||
@@ -83,35 +88,52 @@ internal class DX12GraphicsDevice : IGraphicsDevice
|
||||
queue = _device.CreateCommandQueue(queueDesc);
|
||||
}
|
||||
|
||||
public IRenderView CreateRenderView(in SwapChainSurface swapChainSurface)
|
||||
public IRenderView CreateRenderView(in SwapChainPresenter swapChainSurface)
|
||||
{
|
||||
var renderView = new DX12RenderView(this, swapChainSurface);
|
||||
_renderViews.Add(renderView);
|
||||
lock (_lock)
|
||||
{
|
||||
_renderViews.Add(renderView);
|
||||
}
|
||||
|
||||
return renderView;
|
||||
}
|
||||
|
||||
public void OnRender()
|
||||
{
|
||||
foreach (var renderView in _renderViews)
|
||||
lock (_lock)
|
||||
{
|
||||
renderView.Render();
|
||||
foreach (var renderView in _renderViews)
|
||||
{
|
||||
renderView.ExecutePendingResize();
|
||||
|
||||
renderView.BeginRender();
|
||||
renderView.Render();
|
||||
renderView.EndRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var renderView in _renderViews)
|
||||
{
|
||||
renderView.Dispose();
|
||||
}
|
||||
_renderViews.Clear();
|
||||
|
||||
_commandQueue?.Dispose();
|
||||
_device?.Dispose();
|
||||
_dxgiFactory?.Dispose();
|
||||
_commandQueue.Release();
|
||||
_device.Release();
|
||||
_dxgiFactory.Release();
|
||||
|
||||
#if DEBUG
|
||||
_debugLayer.Dispose();
|
||||
#endif
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.Data;
|
||||
using Ghost.Graphics.DX12.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Vortice.Direct3D12;
|
||||
using Vortice.DXGI;
|
||||
|
||||
@@ -13,6 +12,7 @@ internal class DX12RenderView : IRenderView
|
||||
private const int _DEPTH_STENCIL_VIEW_HEAP_SIZE = 256;
|
||||
|
||||
private readonly DX12GraphicsDevice _graphicsDevice;
|
||||
private readonly SwapChainPresenter _swapChainPresenter;
|
||||
|
||||
private readonly IDXGISwapChain4 _swapChain;
|
||||
private readonly ID3D12Resource[] _renderTargets;
|
||||
@@ -20,7 +20,7 @@ internal class DX12RenderView : IRenderView
|
||||
private uint _backBufferIndex;
|
||||
|
||||
private readonly ID3D12CommandAllocator[] _commandAllocators;
|
||||
private readonly ID3D12GraphicsCommandList7 _commandList;
|
||||
private readonly ID3D12GraphicsCommandList10 _commandList;
|
||||
|
||||
private readonly ID3D12Fence1 _fence;
|
||||
private readonly AutoResetEvent _fenceEvent;
|
||||
@@ -28,9 +28,19 @@ internal class DX12RenderView : IRenderView
|
||||
|
||||
private readonly D3D12DescriptorAllocator _rtvHeap;
|
||||
|
||||
public DX12RenderView(DX12GraphicsDevice pipelineContext, in SwapChainSurface swapChainSurface)
|
||||
private readonly ICommandBuffer _commandBuffer;
|
||||
|
||||
private readonly Lock _lock = new();
|
||||
private uint _pendingWidth;
|
||||
private uint _pendingHeight;
|
||||
private bool _resizeRequested;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public DX12RenderView(DX12GraphicsDevice graphicsDevice, in SwapChainPresenter swapChainSurface)
|
||||
{
|
||||
_graphicsDevice = pipelineContext;
|
||||
_graphicsDevice = graphicsDevice;
|
||||
_swapChainPresenter = swapChainSurface;
|
||||
|
||||
_rtvHeap = new(_graphicsDevice.Device, DescriptorHeapType.RenderTargetView, _RENDER_TARGET_VIEW_HEAP_SIZE);
|
||||
|
||||
@@ -39,21 +49,23 @@ internal class DX12RenderView : IRenderView
|
||||
_fenceValues = new ulong[GraphicsPipeline.FRAME_COUNT];
|
||||
_renderTargetDescriptorIndexes = new uint[GraphicsPipeline.FRAME_COUNT];
|
||||
|
||||
InitializeSwapChain(swapChainSurface, out _swapChain);
|
||||
InitializeSwapChain(out _swapChain);
|
||||
InitializeCommandObjects(out _commandAllocators, out _commandList, out _fence);
|
||||
CreateRenderTargets();
|
||||
|
||||
_commandBuffer = new DX12CommandBuffer(_commandList);
|
||||
}
|
||||
|
||||
private void InitializeSwapChain(in SwapChainSurface swapChainSurface, out IDXGISwapChain4 swapChain)
|
||||
private void InitializeSwapChain(out IDXGISwapChain4 swapChain)
|
||||
{
|
||||
var swapChainDesc = new SwapChainDescription1
|
||||
{
|
||||
Width = swapChainSurface.Width,
|
||||
Height = swapChainSurface.Height,
|
||||
Width = _swapChainPresenter.Width,
|
||||
Height = _swapChainPresenter.Height,
|
||||
Format = Format.B8G8R8A8_UNorm,
|
||||
Stereo = false,
|
||||
SampleDescription = new SampleDescription(1, 0),
|
||||
BufferUsage = Usage.RenderTargetOutput,
|
||||
BufferUsage = Usage.Backbuffer | Usage.RenderTargetOutput,
|
||||
BufferCount = GraphicsPipeline.FRAME_COUNT,
|
||||
Scaling = Scaling.Stretch,
|
||||
SwapEffect = SwapEffect.FlipDiscard,
|
||||
@@ -61,36 +73,37 @@ internal class DX12RenderView : IRenderView
|
||||
Flags = SwapChainFlags.AllowTearing
|
||||
};
|
||||
|
||||
// NOTE: Not going to need it for now, this is for standalone applications.
|
||||
var swapChainFullscreenDesc = new SwapChainFullscreenDescription
|
||||
switch (_swapChainPresenter.Type)
|
||||
{
|
||||
Windowed = true,
|
||||
};
|
||||
|
||||
switch (swapChainSurface.Type)
|
||||
{
|
||||
case SwapChainSurface.TargetType.Composition:
|
||||
case SwapChainPresenter.TargetType.Composition:
|
||||
var swapChain1 = _graphicsDevice.DXGIFactory.CreateSwapChainForComposition(_graphicsDevice.CommandQueue, swapChainDesc);
|
||||
swapChain = swapChain1.QueryInterface<IDXGISwapChain4>();
|
||||
swapChain1.Dispose();
|
||||
|
||||
_backBufferIndex = swapChain.CurrentBackBufferIndex;
|
||||
swapChainSurface.SwapChainPanelNative!.SetSwapChain(swapChain);
|
||||
_swapChainPresenter.SwapChainPanelNative!.SetSwapChain(swapChain);
|
||||
break;
|
||||
case SwapChainSurface.TargetType.Hwnd:
|
||||
case SwapChainPresenter.TargetType.Hwnd:
|
||||
var swapChainFullscreenDesc = new SwapChainFullscreenDescription
|
||||
{
|
||||
Windowed = true,
|
||||
};
|
||||
|
||||
var swapChain2 = _graphicsDevice.DXGIFactory.CreateSwapChainForHwnd(
|
||||
_graphicsDevice.CommandQueue,
|
||||
swapChainSurface.Hwnd,
|
||||
_swapChainPresenter.Hwnd,
|
||||
swapChainDesc,
|
||||
swapChainFullscreenDesc,
|
||||
null);
|
||||
swapChain = swapChain2.QueryInterface<IDXGISwapChain4>();
|
||||
swapChain2.Dispose();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Unsupported swap chain surface type.");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeCommandObjects(out ID3D12CommandAllocator[] commandAllocator, out ID3D12GraphicsCommandList7 commandList, out ID3D12Fence1 fence)
|
||||
private void InitializeCommandObjects(out ID3D12CommandAllocator[] commandAllocator, out ID3D12GraphicsCommandList10 commandList, out ID3D12Fence1 fence)
|
||||
{
|
||||
commandAllocator = new ID3D12CommandAllocator[GraphicsPipeline.FRAME_COUNT];
|
||||
for (var i = 0; i < GraphicsPipeline.FRAME_COUNT; i++)
|
||||
@@ -98,10 +111,10 @@ internal class DX12RenderView : IRenderView
|
||||
commandAllocator[i] = _graphicsDevice.Device.CreateCommandAllocator(CommandListType.Direct);
|
||||
}
|
||||
|
||||
commandList = _graphicsDevice.Device.CreateCommandList<ID3D12GraphicsCommandList7>(CommandListType.Direct, commandAllocator[0], null!);
|
||||
commandList = _graphicsDevice.Device.CreateCommandList<ID3D12GraphicsCommandList10>(CommandListType.Direct, commandAllocator[0], null!);
|
||||
commandList.Close();
|
||||
fence = _graphicsDevice.Device.CreateFence<ID3D12Fence1>(_fenceValues[_backBufferIndex], FenceFlags.None);
|
||||
|
||||
_commandList.Close();
|
||||
_fenceValues[_backBufferIndex]++;
|
||||
}
|
||||
|
||||
@@ -118,32 +131,80 @@ internal class DX12RenderView : IRenderView
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(uint width, uint height)
|
||||
public void RequestResize(uint width, uint height)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_pendingWidth == width && _pendingHeight == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_resizeRequested = true;
|
||||
_pendingWidth = width;
|
||||
_pendingHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecutePendingResize()
|
||||
{
|
||||
if (!_resizeRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint newWidth;
|
||||
uint newHeight;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
newWidth = _pendingWidth;
|
||||
newHeight = _pendingHeight;
|
||||
_resizeRequested = false;
|
||||
}
|
||||
|
||||
WaitIdle();
|
||||
|
||||
for (var i = 0; i < GraphicsPipeline.FRAME_COUNT; i++)
|
||||
{
|
||||
_renderTargets[i].Dispose();
|
||||
_rtvHeap.ReleaseDescriptor(_renderTargetDescriptorIndexes[i]);
|
||||
if (_renderTargets[i] is not null)
|
||||
{
|
||||
_renderTargets[i].Dispose();
|
||||
_rtvHeap.ReleaseDescriptor(_renderTargetDescriptorIndexes[i]);
|
||||
}
|
||||
|
||||
_fenceValues[i] = _fenceValues[_backBufferIndex];
|
||||
}
|
||||
|
||||
_swapChain.ResizeBuffers(GraphicsPipeline.FRAME_COUNT, width, height, Format.B8G8R8A8_UNorm, SwapChainFlags.AllowTearing).CheckError();
|
||||
_swapChain.ResizeBuffers(GraphicsPipeline.FRAME_COUNT, newWidth, newHeight, Format.B8G8R8A8_UNorm, SwapChainFlags.AllowTearing).CheckError();
|
||||
|
||||
CreateRenderTargets();
|
||||
_backBufferIndex = _swapChain.CurrentBackBufferIndex;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
public ICommandBuffer BeginRender()
|
||||
{
|
||||
_backBufferIndex = _swapChain.CurrentBackBufferIndex;
|
||||
|
||||
var commandAllocator = _commandAllocators[_backBufferIndex];
|
||||
commandAllocator.Reset();
|
||||
_commandList.Reset(commandAllocator, null);
|
||||
|
||||
_commandList.ResourceBarrierTransition(_renderTargets[_backBufferIndex], ResourceStates.Present, ResourceStates.RenderTarget);
|
||||
|
||||
return _commandBuffer;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
}
|
||||
|
||||
public void EndRender()
|
||||
{
|
||||
_commandList.ResourceBarrierTransition(_renderTargets[_backBufferIndex], ResourceStates.RenderTarget, ResourceStates.Present);
|
||||
_commandList.Close();
|
||||
_graphicsDevice.CommandQueue.ExecuteCommandLists([_commandList]);
|
||||
|
||||
_graphicsDevice.CommandQueue.ExecuteCommandLists(new[] { _commandList });
|
||||
|
||||
_swapChain.Present(1, PresentFlags.None).CheckError();
|
||||
|
||||
@@ -159,7 +220,6 @@ internal class DX12RenderView : IRenderView
|
||||
return;
|
||||
}
|
||||
|
||||
_backBufferIndex = _swapChain.CurrentBackBufferIndex;
|
||||
if (_fence.CompletedValue < _fenceValues[_backBufferIndex]
|
||||
&& _fence.SetEventOnCompletion(_fenceValues[_backBufferIndex], _fenceEvent.SafeWaitHandle.DangerousGetHandle()).Success)
|
||||
{
|
||||
@@ -172,38 +232,36 @@ internal class DX12RenderView : IRenderView
|
||||
public void WaitIdle()
|
||||
{
|
||||
var fenceValue = _fenceValues[_backBufferIndex];
|
||||
if (_graphicsDevice.CommandQueue.Signal(_fence, fenceValue).Failure
|
||||
|| _fence.SetEventOnCompletion(fenceValue, _fenceEvent.SafeWaitHandle.DangerousGetHandle()).Failure)
|
||||
if (_graphicsDevice.CommandQueue.Signal(_fence, fenceValue).Success
|
||||
&& _fence.SetEventOnCompletion(fenceValue, _fenceEvent.SafeWaitHandle.DangerousGetHandle()).Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_fenceEvent.WaitOne();
|
||||
_fenceValues[_backBufferIndex]++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Flush()
|
||||
{
|
||||
for (var i = 0; i < GraphicsPipeline.FRAME_COUNT; i++)
|
||||
{
|
||||
WaitIdle();
|
||||
_fenceEvent.WaitOne();
|
||||
_fenceValues[_backBufferIndex]++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Flush();
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WaitIdle();
|
||||
|
||||
_swapChainPresenter.SwapChainPanelNative?.SetSwapChain(null);
|
||||
|
||||
foreach (var commandAllocator in _commandAllocators)
|
||||
{
|
||||
commandAllocator.Dispose();
|
||||
}
|
||||
_commandAllocators.AsSpan().Clear();
|
||||
|
||||
foreach (var renderTarget in _renderTargets)
|
||||
{
|
||||
renderTarget.Dispose();
|
||||
}
|
||||
_renderTargets.AsSpan().Clear();
|
||||
|
||||
_swapChain.Dispose();
|
||||
_commandList.Dispose();
|
||||
@@ -215,5 +273,7 @@ internal class DX12RenderView : IRenderView
|
||||
|
||||
_backBufferIndex = 0;
|
||||
_fenceValues.AsSpan().Clear();
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
@@ -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