forked from Misaki/GhostEngine
Add new interfaces and refactor rendering logic
Added a new `ConstPtr<T>` struct for type-safe pointers. Added a new `ICommandBuffer` interface for resource copying. Added a new `IRenderPass` interface to define render passes. Added a new `IResource` interface for GPU resources. Added a new `IResourceAllocator` interface for resource management. Added a new `ISwapChainPanelNative` struct for native interactions. Added a new `D3D12Utility` class for Direct3D 12 utilities. Added a new package reference for `Vortice.Win32.Graphics.D3D12MemoryAllocator`. Changed project file to allow unsafe code blocks. Changed `Result` struct methods to improve clarity. Changed error handling in `ProjectService` and `AssetDatabase` to use `Result.Failure()`. Changed `launchSettings.json` to enable native debugging. Changed rendering logic in `ScenePage.xaml.cs` to use `IRenderer`. Changed `IGraphicsDevice` interface to include renderer properties. Changed `IRenderView` to `IRenderer` and updated its methods. Changed `Mesh` class to use the new `IResource` interface for buffers. Changed `GraphicsAPI` enum to include a `None` value. Changed various aspects of the `GraphicsPipeline` class for new architecture. Removed the old `DX12RenderView` class and replaced it with `DX12Renderer`. Removed unnecessary code in the `ResourceView` class.
This commit is contained in:
252
Ghost.Graphics/DX12/DX12ResourceAllocator.cs
Normal file
252
Ghost.Graphics/DX12/DX12ResourceAllocator.cs
Normal file
@@ -0,0 +1,252 @@
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.DX12.Utilities;
|
||||
using Ghost.Graphics.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Vortice.Direct3D12;
|
||||
using Vortice.DXGI;
|
||||
|
||||
namespace Ghost.Graphics.DX12;
|
||||
|
||||
internal unsafe class DX12ResourceAllocator : IResourceAllocator
|
||||
{
|
||||
private const ResourceStates _INITIALCOPYTARGETSTATE = ResourceStates.Common;
|
||||
private const ResourceStates _INITIALREADTARGETSTATE = ResourceStates.Common;
|
||||
private const ResourceStates _INITIALUAVTARGETSTATE = ResourceStates.Common;
|
||||
|
||||
private const uint _MAX_BYTES = D3D12.RequestResourceSizeInMegaBytesExpressionATerm * 1024u * 1024u;
|
||||
|
||||
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);
|
||||
if (sizeInBytes > _MAX_BYTES)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (sizeInBytes > _MAX_BYTES)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (sizeInBytes > _MAX_BYTES)
|
||||
{
|
||||
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 CreateUAVBuffer(ID3D12Device device, uint bufferSize,
|
||||
ResourceStates initialState = ResourceStates.Common,
|
||||
ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
if (bufferSize > _MAX_BYTES)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public static IResourceAllocator Create() => new DX12ResourceAllocator();
|
||||
|
||||
public IResource CreateUploadBuffer(uint sizeInBytes, ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
if (sizeInBytes > _MAX_BYTES)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
|
||||
var device = GraphicsPipeline.GetRenderer<DX12GraphicsDevice>();
|
||||
var buffer = device.NativeDevice.CreateCommittedResource(
|
||||
HeapType.Upload,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
ResourceStates.GenericRead
|
||||
);
|
||||
|
||||
return new DX12Resource(buffer);
|
||||
}
|
||||
|
||||
public IResource CreateCopyDestinationBuffer(uint sizeInBytes, ResourceFlags flags = ResourceFlags.None)
|
||||
{
|
||||
if (sizeInBytes > _MAX_BYTES)
|
||||
{
|
||||
throw new InvalidOperationException($"ERROR: Resource size too large for DirectX 12 (size {sizeInBytes})");
|
||||
}
|
||||
|
||||
var device = GraphicsPipeline.GetRenderer<DX12GraphicsDevice>();
|
||||
var buffer = device.NativeDevice.CreateCommittedResource(
|
||||
HeapType.Default,
|
||||
HeapFlags.None,
|
||||
ResourceDescription.Buffer(sizeInBytes, flags),
|
||||
ResourceStates.CopyDest
|
||||
);
|
||||
|
||||
return new DX12Resource(buffer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user