feat(rendergraph): async queue, pool refactor, barrier cleanup
Refactor resource pool to use UnsafeQueue/UnsafeList for transient resources, improving memory management and performance. Add async GPU wait support to ICommandQueue and D3D12. Refactor render graph barrier system, streamline CompiledBarrier, and remove ResourceBarrier. RenderGraphCompiler now returns Result<float2, Error> for dynamic resolution scaling. Replace custom memory pools with Allocator.FreeList for temp allocations. Add ResourceUploadBatch for async/sync resource uploads. Fix D3D12 disposal and fence tracking bugs. Update NuGet dependencies. Numerous minor cleanups and code improvements.
This commit is contained in:
@@ -22,8 +22,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
{
|
||||
private class MeshletDebugPassData
|
||||
{
|
||||
public Identifier<RGTexture> depth;
|
||||
public Identifier<RGTexture> backbuffer;
|
||||
public RenderList renderList;
|
||||
public Handle<Material> material;
|
||||
public uint globalIndex;
|
||||
@@ -72,7 +70,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
renderSystem.GraphicsEngine.ShaderCompiler.CompilePass(in pass, in config, variantKey).GetValueOrThrow();
|
||||
}
|
||||
|
||||
|
||||
private static float3 IntersectFrustumPlanes(float4 p0, float4 p1, float4 p2)
|
||||
{
|
||||
var n0 = p0.xyz;
|
||||
@@ -139,10 +136,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
continue;
|
||||
}
|
||||
|
||||
Handle<GPUBuffer> instanceBufferHandle = default;
|
||||
Handle<GPUBuffer> viewBufferHandle = default;
|
||||
Handle<GPUBuffer> frameBufferHandle = default;
|
||||
|
||||
try
|
||||
{
|
||||
var rtResult = _renderSystem.GraphicsEngine.ResourceDatabase.GetResourceDescription(rt.AsResource());
|
||||
@@ -226,7 +219,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
HeapType = HeapType.Upload, // Upload directly for simplicity in testing
|
||||
};
|
||||
|
||||
instanceBufferHandle = resourceManager.CreateTransientBuffer(in instanceBufferDesc, "Instance Buffer");
|
||||
var instanceBufferHandle = resourceManager.CreateTransientBuffer(in instanceBufferDesc, "Instance Buffer");
|
||||
var instanceBufferResource = instanceBufferHandle.AsResource();
|
||||
|
||||
var instanceDataArray = new InstanceData[instanceCount];
|
||||
@@ -266,7 +259,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
viewBufferHandle = resourceManager.CreateTransientBuffer(in viewBufferDesc, "View Buffer");
|
||||
var viewBufferHandle = resourceManager.CreateTransientBuffer(in viewBufferDesc, "View Buffer");
|
||||
var viewBufferResource = viewBufferHandle.AsResource();
|
||||
|
||||
var viewData = new ViewData
|
||||
@@ -294,7 +287,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||
var frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||
var frameBufferResource = frameBufferHandle.AsResource();
|
||||
|
||||
var frameData = new FrameData
|
||||
@@ -329,10 +322,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
}
|
||||
finally
|
||||
{
|
||||
_renderSystem.GraphicsEngine.ResourceDatabase.ReleaseResource(instanceBufferHandle.AsResource());
|
||||
_renderSystem.GraphicsEngine.ResourceDatabase.ReleaseResource(viewBufferHandle.AsResource());
|
||||
_renderSystem.GraphicsEngine.ResourceDatabase.ReleaseResource(frameBufferHandle.AsResource());
|
||||
|
||||
if (request.swapChainIndex >= 0)
|
||||
{
|
||||
_renderSystem.SwapChainManager.ReleaseSwapChain(request.swapChainIndex);
|
||||
@@ -347,8 +336,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
{
|
||||
var depth = builder.CreateTexture(RGTextureDesc.RelativeDepth(1.0f), "Depth Texture");
|
||||
|
||||
passData.depth = depth;
|
||||
passData.backbuffer = backbuffer;
|
||||
passData.renderList = renderList;
|
||||
passData.globalIndex = globalIndex;
|
||||
passData.viewIndex = viewIndex;
|
||||
|
||||
@@ -39,6 +39,7 @@ internal static class MeshUtility
|
||||
return Result.Failure("Unsupported file format. Only .obj and .fbx are supported.");
|
||||
}
|
||||
|
||||
var error = new ufbx_error();
|
||||
var load_Opts = new ufbx_load_opts
|
||||
{
|
||||
target_axes = ufbx_coordinate_axes.left_handed_y_up,
|
||||
@@ -48,15 +49,8 @@ internal static class MeshUtility
|
||||
handedness_conversion_axis = ufbx_mirror_axis.UFBX_MIRROR_AXIS_X,
|
||||
space_conversion = ufbx_space_conversion.UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY,
|
||||
};
|
||||
var error = new ufbx_error();
|
||||
|
||||
using var pool = new MemoryPool<VirtualStack, VirtualStack.CreationOpts>(new VirtualStack.CreationOpts
|
||||
{
|
||||
reserveCapacity = 256 * 1024 * 1024 // 256 MB should be enough for most models, adjust as needed. Note that this use virtual memory and does not actually consume physical memory until allocations are made.
|
||||
});
|
||||
|
||||
using var scope0 = pool.Allocator.CreateScope(pool.AllocationHandle);
|
||||
using var str = new UnsafeArray<byte>(Encoding.UTF8.GetByteCount(filePath) + 1, scope0.AllocationHandle);
|
||||
using var str = new UnsafeArray<byte>(Encoding.UTF8.GetByteCount(filePath) + 1, Allocator.FreeList);
|
||||
var count = Encoding.UTF8.GetBytes(filePath, str.AsSpan());
|
||||
str[count] = 0;
|
||||
|
||||
@@ -66,7 +60,7 @@ internal static class MeshUtility
|
||||
return Result.Failure(error.description.ToString());
|
||||
}
|
||||
|
||||
using var flatVertices = new UnsafeList<Vertex>(1024, scope0.AllocationHandle);
|
||||
using var flatVertices = new UnsafeList<Vertex>(1024, Allocator.FreeList);
|
||||
|
||||
var needComputeNormals = false;
|
||||
|
||||
@@ -78,8 +72,6 @@ internal static class MeshUtility
|
||||
continue;
|
||||
}
|
||||
|
||||
using var scope1 = pool.Allocator.CreateScope(pool.AllocationHandle);
|
||||
|
||||
if (node->mesh != null)
|
||||
{
|
||||
var pMesh = node->mesh;
|
||||
@@ -90,7 +82,7 @@ internal static class MeshUtility
|
||||
|
||||
var maxScratchIndices = (int)(pMesh->max_face_triangles * 3u);
|
||||
|
||||
var triIndicesArray = new UnsafeArray<uint>(maxScratchIndices, scope1.AllocationHandle);
|
||||
using var triIndicesArray = new UnsafeArray<uint>(maxScratchIndices, Allocator.FreeList);
|
||||
|
||||
for (var j = 0u; j < pMesh->num_faces; j++)
|
||||
{
|
||||
@@ -141,8 +133,8 @@ internal static class MeshUtility
|
||||
|
||||
var numIndices = (uint)flatVertices.Count;
|
||||
|
||||
using var weldedIndices = new UnsafeArray<uint>((int)numIndices, scope0.AllocationHandle);
|
||||
using var cachedIndices = new UnsafeArray<uint>((int)numIndices, scope0.AllocationHandle);
|
||||
using var weldedIndices = new UnsafeArray<uint>((int)numIndices, Allocator.FreeList);
|
||||
using var cachedIndices = new UnsafeArray<uint>((int)numIndices, Allocator.FreeList);
|
||||
|
||||
var stream = new ufbx_vertex_stream
|
||||
{
|
||||
|
||||
@@ -35,14 +35,7 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
Panel.SizeChanged += SwapChainPanel_SizeChanged;
|
||||
Panel.CompositionScaleChanged += SwapChainPanel_CompositionScaleChanged;
|
||||
|
||||
var opts = new AllocationManagerInitOpts
|
||||
{
|
||||
ArenaCapacity = 1024 * 1024 * 1024, // 1GB
|
||||
StackCapacity = 1024 * 1024 * 32, // 32MB
|
||||
FreeListConcurrencyLevel = Environment.ProcessorCount,
|
||||
};
|
||||
|
||||
AllocationManager.Initialize(opts);
|
||||
AllocationManager.Initialize(AllocationManagerInitOpts.Default);
|
||||
|
||||
//_jobScheduler = new JobScheduler(Environment.ProcessorCount - 1);
|
||||
}
|
||||
@@ -90,7 +83,7 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
// Create Camera Entity
|
||||
|
||||
using var scope = AllocationManager.CreateStackScope();
|
||||
var camSet = new ComponentSet(scope.AllocationHandle, ComponentTypeID<Camera>.Value, ComponentTypeID<LocalToWorld>.Value);
|
||||
using var camSet = new ComponentSet(scope.AllocationHandle, ComponentTypeID<Camera>.Value, ComponentTypeID<LocalToWorld>.Value);
|
||||
var cameraEntity = _world.EntityManager.CreateEntity(camSet);
|
||||
|
||||
_world.EntityManager.SetComponent(cameraEntity, new Camera
|
||||
@@ -126,12 +119,10 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
|
||||
directCmd.End().ThrowIfFailed();
|
||||
|
||||
// FIX: This will bump the complete value of the queue and cause the render thread render the first frame twice, which is not expected. We should have a better way to handle this.
|
||||
// Maybe a async upload support in the future?
|
||||
// Maybe async upload support in the future?
|
||||
_renderSystem.GraphicsEngine.Device.GraphicsQueue.Submit(directCmd);
|
||||
_renderSystem.GraphicsEngine.Device.GraphicsQueue.WaitIdle();
|
||||
|
||||
var meshSet = new ComponentSet(scope.AllocationHandle, ComponentTypeID<MeshInstance>.Value, ComponentTypeID<LocalToWorld>.Value);
|
||||
using var meshSet = new ComponentSet(scope.AllocationHandle, ComponentTypeID<MeshInstance>.Value, ComponentTypeID<LocalToWorld>.Value);
|
||||
var meshEntity = _world.EntityManager.CreateEntity(meshSet);
|
||||
_world.EntityManager.SetComponent(meshEntity, new MeshInstance
|
||||
{
|
||||
@@ -208,7 +199,6 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
|
||||
if (_renderSystem.TryAcquireCPUFrame())
|
||||
{
|
||||
Debug.WriteLine($"CPU: Frame started.");
|
||||
_world.SystemManager.UpdateAll(default);
|
||||
_renderSystem.SignalCPUReady();
|
||||
}
|
||||
|
||||
@@ -117,20 +117,25 @@ internal sealed unsafe class NvttBindingTest : ITest
|
||||
pOutOpts->SetSrgbFlag(true);
|
||||
pOutOpts->SetContainer(NvttContainer.NVTT_Container_DDS10);
|
||||
|
||||
pOutOpts->SetOutputHandler(
|
||||
(size, w, h, d, face, mip) =>
|
||||
using var handler = new NvttOutputHandler
|
||||
{
|
||||
beginImageHandler = (size, w, h, d, face, mip) =>
|
||||
{
|
||||
imagesBegun++;
|
||||
},
|
||||
(ptr, len) =>
|
||||
outputHandler = (ptr, len) =>
|
||||
{
|
||||
totalBytesReceived += len;
|
||||
return true;
|
||||
},
|
||||
null
|
||||
);
|
||||
pOutOpts->SetErrorHandler(err =>
|
||||
Console.WriteLine($"/n [NVTT Error] {err}"));
|
||||
endImageHandler = null,
|
||||
errorHandler = (err) =>
|
||||
{
|
||||
Console.WriteLine($"/n [NVTT Error] {err}");
|
||||
}
|
||||
};
|
||||
|
||||
pOutOpts->SetOutputHandler(handler);
|
||||
|
||||
var pCtx = NvttContext.Create();
|
||||
pCtx->SetCudaAcceleration(false); // CPU only for the test
|
||||
@@ -214,7 +219,7 @@ internal sealed unsafe class NvttBindingTest : ITest
|
||||
{
|
||||
(*(int*)userData)++;
|
||||
|
||||
int i = 0;
|
||||
var i = 0;
|
||||
while (msg[i] != 0)
|
||||
{
|
||||
i++;
|
||||
|
||||
Reference in New Issue
Block a user