feat(engine)!: refactor graphics, ECS, and logging APIs

Major refactor of graphics and ECS infrastructure:
- Removed IResourceManager, IRenderSystem, IFenceSynchronizer interfaces; ResourceManager and RenderSystem are now concrete classes.
- Updated all render graph, pipeline, and context code to use concrete ResourceManager.
- Refactored camera/frustum math and render extraction for clarity and correctness; frustum now uses inline arrays.
- RenderingLayerMask is now an immutable struct with bitwise operators.
- Meshlet and meshlet group data structures improved; meshlet build callback signature updated.
- Logging system overhauled: LogMessage is now a class, LogCollection supports change events, and Logger is used directly in the debug console.
- ECS query API: ChunkView.Count renamed to EntityCount; query builder/iterators use VirtualStack.Scope.
- Updated render pipeline and passes for new resource manager and render list APIs.
- Cleaned up obsolete files, improved code style, and updated documentation.
- HLSL meshlet shader updated for new struct layout.
- Debug console now uses new logger and log collection.

BREAKING CHANGE: Public APIs for resource management, rendering, ECS queries, and logging have changed. Interfaces removed; use new concrete types and updated method signatures.
This commit is contained in:
2026-03-21 22:10:28 +09:00
parent 793df1af4f
commit 37f4795b4f
45 changed files with 1007 additions and 840 deletions

View File

@@ -6,34 +6,12 @@ using System.Collections.Concurrent;
namespace Ghost.Graphics;
public interface IRenderSystem : IFenceSynchronizer, IDisposable
{
IGraphicsEngine GraphicsEngine
{
get;
}
IResourceManager ResourceManager
{
get;
}
bool IsRunning
{
get;
}
void Start();
void Stop();
void RequestSwapChainResize(ISwapChain swapChain, uint2 newSize);
}
public enum GraphicsAPI
internal enum GraphicsAPI
{
Direct3D12
}
public struct RenderSystemDesc
internal struct RenderSystemDesc
{
public GraphicsAPI GraphicsAPI
{
@@ -50,9 +28,8 @@ public struct RenderSystemDesc
/// Application-level render system that orchestrates multiple renderers
/// and handles frame synchronization
/// </summary>
internal class RenderSystem : IRenderSystem
public class RenderSystem : IDisposable
{
// TODO: Thread local command buffers.
private struct FrameResource : IDisposable
{
public required AutoResetEvent CpuReadyEvent
@@ -85,7 +62,7 @@ internal class RenderSystem : IRenderSystem
private readonly RenderSystemDesc _config;
private readonly IGraphicsEngine _graphicsEngine;
private readonly IResourceManager _resourceManager;
private readonly ResourceManager _resourceManager;
private readonly FrameResource[] _frameResources;
private readonly Thread _renderThread;
@@ -100,7 +77,7 @@ internal class RenderSystem : IRenderSystem
private bool _disposed;
public IGraphicsEngine GraphicsEngine => _graphicsEngine;
public IResourceManager ResourceManager => _resourceManager;
public ResourceManager ResourceManager => _resourceManager;
public bool IsRunning => _isRunning;
public uint CPUFenceValue => _cpuFenceValue;
@@ -108,7 +85,7 @@ internal class RenderSystem : IRenderSystem
public uint FrameIndex => _frameIndex;
public uint MaxFrameLatency => _config.FrameBufferCount;
public RenderSystem(RenderSystemDesc desc)
internal RenderSystem(RenderSystemDesc desc)
{
_config = desc;
@@ -169,67 +146,6 @@ internal class RenderSystem : IRenderSystem
Dispose();
}
public void Start()
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (_isRunning)
{
return;
}
_isRunning = true;
_renderThread.Start();
}
public void Stop()
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!_isRunning)
{
return;
}
_isRunning = false;
_shutdownEvent.Set();
_renderThread.Join();
}
public void RequestSwapChainResize(ISwapChain swapChain, uint2 newSize)
{
ObjectDisposedException.ThrowIf(_disposed, this);
_resizeRequest.AddOrUpdate(swapChain, newSize, (_, _) => newSize);
}
public bool WaitForGPUReady(int timeOut = -1)
{
ObjectDisposedException.ThrowIf(_disposed, this);
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
return _frameResources[eventIndex].GpuReadyEvent.WaitOne(timeOut);
}
public void SignalCPUReady()
{
ObjectDisposedException.ThrowIf(_disposed, this);
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
_frameResources[eventIndex].CpuReadyEvent.Set();
_cpuFenceValue++;
}
public void WaitIdle()
{
foreach (var frameResource in _frameResources)
{
if (frameResource.FenceValue > 0)
{
_graphicsEngine.Device.GraphicsQueue.WaitForValue(frameResource.FenceValue);
}
}
}
private void RenderLoop()
{
var waitHandles = new WaitHandle[] { null!, _shutdownEvent };
@@ -272,14 +188,16 @@ internal class RenderSystem : IRenderSystem
resource.CommandAllocator.Reset();
}
foreach (var kvp in _resizeRequest)
var keys = _resizeRequest.Keys.ToArray();
foreach (var swapChain in keys)
{
var swapChain = kvp.Key;
var newSize = kvp.Value;
swapChain.Resize(newSize.x, newSize.y);
if (_resizeRequest.TryRemove(swapChain, out var newSize))
{
swapChain.Resize(newSize.x, newSize.y);
}
}
_resizeRequest.Clear();
frameResource.GpuReadyEvent.Set();
continue; // Skip rendering this frame since we just resized and may have invalid render targets
}
@@ -304,6 +222,67 @@ internal class RenderSystem : IRenderSystem
}
}
internal void Start()
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (_isRunning)
{
return;
}
_isRunning = true;
_renderThread.Start();
}
internal void Stop()
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!_isRunning)
{
return;
}
_isRunning = false;
_shutdownEvent.Set();
_renderThread.Join();
}
internal void SignalCPUReady()
{
ObjectDisposedException.ThrowIf(_disposed, this);
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
_frameResources[eventIndex].CpuReadyEvent.Set();
_cpuFenceValue++;
}
internal void RequestSwapChainResize(ISwapChain swapChain, uint2 newSize)
{
ObjectDisposedException.ThrowIf(_disposed, this);
_resizeRequest.AddOrUpdate(swapChain, newSize, (_, _) => newSize);
}
public bool WaitForGPUReady(int timeOut = -1)
{
ObjectDisposedException.ThrowIf(_disposed, this);
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
return _frameResources[eventIndex].GpuReadyEvent.WaitOne(timeOut);
}
public void WaitIdle()
{
foreach (var frameResource in _frameResources)
{
if (frameResource.FenceValue > 0)
{
_graphicsEngine.Device.GraphicsQueue.WaitForValue(frameResource.FenceValue);
}
}
}
public void Dispose()
{
if (_disposed)