Refactor graphics architecture and resource management
Added DescriptorAllocator.cs to manage descriptor allocations for Direct3D 12. Added Texture2D.cs to handle 2D textures and GPU resource creation. Added DescriptorAllocatorExample.cs to demonstrate the new descriptor allocator interface. Changed project files to reference Misaki.HighPerformance.LowLevel instead of Misaki.HighPerformance.Unsafe. Changed _renderView type from IRenderer? to Renderer? in ScenePage.xaml.cs. Changed EngineCore.cs to remove explicit graphics API specification during initialization. Changed Logger.cs to enhance the Assert method with a DoesNotReturnIf attribute. Changed resource types in Mesh.cs from IResource to GraphicsResource. Removed multiple interfaces including ICommandBuffer, IDebugLayer, IGraphicsDevice, IPipelineResource, IRenderPass, IRenderer, IResource, and IResourceAllocator to simplify the graphics architecture. Removed D3D12DebugLayer class from DebugLayer.cs to streamline the debug layer implementation. Updated CommandList.cs and D3D12CommandBuffer.cs to implement a new command list structure for Direct3D 12. Updated Material.cs to improve handling of constant buffers and textures. Updated Shader.cs to include new structures for texture and property information. Updated GraphicsPipeline.cs to support the new graphics device and resource management system. Updated UnitTestAppWindow.xaml.cs to reflect changes in the renderer type and ensure proper resource management. Updated BindlessMeshRenderPass.cs and MeshRenderPass.cs to implement modern rendering techniques, including bindless textures and improved shader management. Updated CBufferCache.cs to align with the new resource management system and improve memory handling.
This commit is contained in:
@@ -1,196 +1,154 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.Contracts;
|
||||
using Ghost.Graphics.D3D12;
|
||||
using Ghost.Graphics.Data;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Ghost.Graphics.D3D12;
|
||||
|
||||
namespace Ghost.Graphics;
|
||||
|
||||
public static class GraphicsPipeline
|
||||
{
|
||||
internal const int _FRAME_COUNT = 2;
|
||||
internal const uint _FRAME_COUNT = 2;
|
||||
|
||||
private static IGraphicsDevice? _graphicsDevice;
|
||||
private static IResourceAllocator? _resourceAllocator;
|
||||
|
||||
private static Thread? _renderThread;
|
||||
private static AutoResetEvent[]? _cpuReadyEvent;
|
||||
private static AutoResetEvent[]? _gpuReadyEvent;
|
||||
|
||||
private static uint _cpuFenceValue;
|
||||
private static uint _gpuFenceValue;
|
||||
|
||||
private static bool _initialized;
|
||||
private static bool _isRunning;
|
||||
|
||||
internal static uint CPUFenceValue => _cpuFenceValue;
|
||||
internal static uint GPUFenceValue => _gpuFenceValue;
|
||||
internal static bool IsRunning => _isRunning;
|
||||
|
||||
internal static IGraphicsDevice GraphicsDevice
|
||||
private readonly struct FrameResource : IDisposable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_graphicsDevice == null)
|
||||
{
|
||||
throw new InvalidOperationException("Graphics pipeline is not initialized.");
|
||||
}
|
||||
public readonly AutoResetEvent cpuReadyEvent;
|
||||
public readonly AutoResetEvent gpuReadyEvent;
|
||||
|
||||
return _graphicsDevice;
|
||||
public FrameResource()
|
||||
{
|
||||
cpuReadyEvent = new(false);
|
||||
gpuReadyEvent = new(true);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cpuReadyEvent?.Dispose();
|
||||
gpuReadyEvent?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal static IResourceAllocator ResourceAllocator
|
||||
private static GraphicsDevice? s_graphicsDevice;
|
||||
private static DescriptorAllocator? s_descriptorAllocator;
|
||||
private static ResourceAllocator? s_resourceAllocator;
|
||||
|
||||
private static Thread? s_renderThread;
|
||||
private static FrameResource[]? s_frameResources;
|
||||
|
||||
private static uint s_frameIndex;
|
||||
private static uint s_cpuFenceValue;
|
||||
private static uint s_gpuFenceValue;
|
||||
|
||||
private static bool s_initialized;
|
||||
private static bool s_isRunning;
|
||||
|
||||
internal static uint CPUFenceValue => s_cpuFenceValue;
|
||||
internal static uint GPUFenceValue => s_gpuFenceValue;
|
||||
internal static bool IsRunning => s_isRunning;
|
||||
|
||||
internal static GraphicsDevice GraphicsDevice => s_graphicsDevice ?? throw new InvalidOperationException("Graphics device is not initialized.");
|
||||
internal static ResourceAllocator ResourceAllocator => s_resourceAllocator ?? throw new InvalidOperationException("Resource allocator is not initialized.");
|
||||
internal static DescriptorAllocator DescriptorAllocator => s_descriptorAllocator ?? throw new InvalidOperationException("Descriptor allocator is not initialized.");
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_resourceAllocator == null)
|
||||
{
|
||||
throw new InvalidOperationException("Resource allocator is not initialized.");
|
||||
}
|
||||
s_graphicsDevice = new GraphicsDevice();
|
||||
s_descriptorAllocator = new DescriptorAllocator();
|
||||
s_resourceAllocator = new ResourceAllocator();
|
||||
|
||||
return _resourceAllocator;
|
||||
}
|
||||
}
|
||||
|
||||
public static GraphicsAPI CurrentAPI
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal static void Initialize(GraphicsAPI api)
|
||||
{
|
||||
switch (api)
|
||||
{
|
||||
case GraphicsAPI.D3D12:
|
||||
_graphicsDevice = new D3D12GraphicsDevice();
|
||||
_resourceAllocator = new D3D12ResourceAllocator();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Graphics API {api} is not supported.");
|
||||
}
|
||||
|
||||
_renderThread = new Thread(RenderLoop)
|
||||
s_renderThread = new Thread(RenderLoop)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "Graphics Render Thread",
|
||||
Priority = ThreadPriority.Normal
|
||||
};
|
||||
|
||||
_cpuReadyEvent = new AutoResetEvent[_FRAME_COUNT];
|
||||
_gpuReadyEvent = new AutoResetEvent[_FRAME_COUNT];
|
||||
s_frameResources = new FrameResource[_FRAME_COUNT];
|
||||
for (var i = 0; i < _FRAME_COUNT; i++)
|
||||
{
|
||||
_cpuReadyEvent[i] = new(false);
|
||||
_gpuReadyEvent[i] = new(true);
|
||||
s_frameResources[i] = new FrameResource();
|
||||
}
|
||||
|
||||
CurrentAPI = api;
|
||||
|
||||
_initialized = true;
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
private static void RenderLoop()
|
||||
{
|
||||
while (_isRunning)
|
||||
while (s_isRunning)
|
||||
{
|
||||
if (_graphicsDevice == null)
|
||||
{
|
||||
throw new ArgumentException("Renderer has been disposed or is not initialized.");
|
||||
}
|
||||
s_frameIndex = s_gpuFenceValue % _FRAME_COUNT;
|
||||
var frameResource = s_frameResources![s_frameIndex];
|
||||
|
||||
var eventIndex = (int)(_gpuFenceValue % _FRAME_COUNT);
|
||||
_cpuReadyEvent![eventIndex].WaitOne();
|
||||
frameResource.cpuReadyEvent.WaitOne();
|
||||
|
||||
_graphicsDevice.InitializePendingRenderers();
|
||||
s_graphicsDevice!.InitializePendingRenderers();
|
||||
|
||||
foreach (var renderer in _graphicsDevice.Renderers)
|
||||
foreach (var renderer in s_graphicsDevice.Renderers)
|
||||
{
|
||||
renderer.ExecutePendingResize();
|
||||
renderer.Render();
|
||||
}
|
||||
|
||||
_gpuFenceValue++;
|
||||
_gpuReadyEvent![eventIndex].Set();
|
||||
s_gpuFenceValue++;
|
||||
frameResource.gpuReadyEvent.Set();
|
||||
|
||||
_resourceAllocator!.ReleaseTempResource();
|
||||
s_resourceAllocator!.ReleaseTempResource();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static bool WaitForGPUReady(int timeOut = -1)
|
||||
{
|
||||
if (_gpuReadyEvent == null)
|
||||
if (s_frameResources == null)
|
||||
{
|
||||
throw new InvalidOperationException("Graphics pipeline is not initialized.");
|
||||
}
|
||||
|
||||
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
||||
return _gpuReadyEvent[eventIndex].WaitOne(timeOut);
|
||||
var eventIndex = (int)(s_cpuFenceValue % _FRAME_COUNT);
|
||||
return s_frameResources[eventIndex].gpuReadyEvent.WaitOne(timeOut);
|
||||
}
|
||||
|
||||
internal static void SignalCPUReady()
|
||||
{
|
||||
if (_cpuReadyEvent == null)
|
||||
if (s_frameResources == null)
|
||||
{
|
||||
throw new InvalidOperationException("Graphics pipeline is not initialized.");
|
||||
}
|
||||
|
||||
var eventIndex = (int)(_cpuFenceValue % _FRAME_COUNT);
|
||||
_cpuFenceValue++;
|
||||
_cpuReadyEvent[eventIndex].Set();
|
||||
var eventIndex = (int)(s_cpuFenceValue % _FRAME_COUNT);
|
||||
s_cpuFenceValue++;
|
||||
s_frameResources[eventIndex].cpuReadyEvent.Set();
|
||||
}
|
||||
|
||||
internal static void Start()
|
||||
{
|
||||
if (_isRunning || !_initialized)
|
||||
if (s_isRunning || !s_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isRunning = true;
|
||||
_renderThread!.Start();
|
||||
s_isRunning = true;
|
||||
s_renderThread!.Start();
|
||||
}
|
||||
|
||||
internal static void Stop()
|
||||
{
|
||||
_isRunning = false;
|
||||
_renderThread?.Join();
|
||||
s_isRunning = false;
|
||||
s_renderThread?.Join();
|
||||
}
|
||||
|
||||
internal static void Shutdown()
|
||||
{
|
||||
Stop();
|
||||
|
||||
_graphicsDevice?.Dispose();
|
||||
_resourceAllocator?.Dispose();
|
||||
s_resourceAllocator?.Dispose();
|
||||
s_descriptorAllocator?.Dispose();
|
||||
s_graphicsDevice?.Dispose();
|
||||
|
||||
_graphicsDevice = null;
|
||||
_renderThread = null;
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static T GetGraphicsDevice<T>()
|
||||
where T : class, IGraphicsDevice
|
||||
{
|
||||
if (T.TargetAPI != CurrentAPI)
|
||||
if (s_frameResources != null)
|
||||
{
|
||||
throw new InvalidOperationException($"No graphics device of type {typeof(T)} available for the current API.");
|
||||
foreach (var frameResource in s_frameResources)
|
||||
{
|
||||
frameResource.Dispose();
|
||||
}
|
||||
s_frameResources = null;
|
||||
}
|
||||
|
||||
return Unsafe.As<T>(GraphicsDevice);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Result CheckAPI(GraphicsAPI expectedAPI)
|
||||
{
|
||||
if (CurrentAPI != expectedAPI)
|
||||
{
|
||||
return Result.Failure($"Expected API {expectedAPI}, but got {CurrentAPI}.");
|
||||
}
|
||||
|
||||
return Result.Success();
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user