Add render graph proof of concept and refactor graphics

Implemented a transient render graph system as a proof of concept, including resource aliasing, pass culling, and typed pass data. Added new project `Ghost.RenderGraph.Concept` targeting `.NET 10.0`.

Refactored graphics-related components:
- Simplified resource state transitions in `RenderingContext`.
- Improved resize handling in `GraphicsTestWindow`.
- Updated `D3D12GraphicsEngine` to streamline frame rendering.
- Enhanced `D3D12ResourceDatabase` and `D3D12SwapChain` for better resource management.

Added detailed documentation:
- `ALIASING.md` explains resource aliasing techniques.
- `API_DESIGN.md` outlines the render graph API design.

Updated solution to include the new render graph project.
This commit is contained in:
2025-12-01 22:31:17 +09:00
parent 85280c746d
commit 676f8bb74c
31 changed files with 2167 additions and 142 deletions

View File

@@ -64,15 +64,12 @@ public readonly unsafe ref struct RenderingContext
var vertexHandle = meshData.VertexBuffer.AsResource();
var indexHandle = meshData.IndexBuffer.AsResource();
_directCmd.ResourceBarrier(vertexHandle, ResourceState.Common, ResourceState.CopyDest);
_directCmd.ResourceBarrier(indexHandle, ResourceState.Common, ResourceState.CopyDest);
_directCmd.ResourceBarrier(vertexHandle, ResourceState.CopyDest);
_directCmd.ResourceBarrier(indexHandle, ResourceState.CopyDest);
_directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan());
_directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan());
_directCmd.ResourceBarrier(vertexHandle, ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
_directCmd.ResourceBarrier(indexHandle, ResourceState.CopyDest, ResourceState.IndexBuffer);
if (staticMesh)
{
meshData.ReleaseCpuResources();
@@ -101,41 +98,20 @@ public readonly unsafe ref struct RenderingContext
/// <param name="markMeshStatic">Whether to mark the mesh as static. If it's true, the cpu buffer of the mesh will not be avaliable any more</param>
public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic)
{
ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
var vertexState = ResourceDatabase.GetResourceState(meshData.VertexBuffer.AsResource())
.GetValueOrThrow(ResultStatus.Success);
var indexState = ResourceDatabase.GetResourceState(meshData.IndexBuffer.AsResource())
.GetValueOrThrow(ResultStatus.Success);
ref var meshRef = ref ResourceDatabase.GetMeshReference(mesh);
var needVertexTransition = vertexState != ResourceState.CopyDest;
var needIndexTransition = indexState != ResourceState.CopyDest;
_directCmd.ResourceBarrier(meshRef.VertexBuffer.AsResource(),ResourceState.CopyDest);
_directCmd.ResourceBarrier(meshRef.IndexBuffer.AsResource(), ResourceState.CopyDest);
if (needVertexTransition)
{
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
}
_directCmd.UploadBuffer(meshRef.VertexBuffer, meshRef.Vertices.AsSpan());
_directCmd.UploadBuffer(meshRef.IndexBuffer, meshRef.Indices.AsSpan());
if (needIndexTransition)
{
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), indexState, ResourceState.CopyDest);
}
_directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan());
_directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan());
if (needVertexTransition)
{
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
}
if (needIndexTransition)
{
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, indexState);
}
_directCmd.ResourceBarrier(meshRef.VertexBuffer.AsResource(), ResourceState.NonPixelShaderResource);
_directCmd.ResourceBarrier(meshRef.IndexBuffer.AsResource(), ResourceState.NonPixelShaderResource);
if (markMeshStatic)
{
meshData.ReleaseCpuResources();
meshRef.ReleaseCpuResources();
}
}
@@ -152,21 +128,10 @@ public readonly unsafe ref struct RenderingContext
};
var bufferHandle = meshData.ObjectDataBuffer.AsResource();
var state = ResourceDatabase.GetResourceState(bufferHandle)
.GetValueOrThrow(ResultStatus.Success);
var needTransition = state != ResourceState.CopyDest;
if (needTransition)
{
_directCmd.ResourceBarrier(bufferHandle, state, ResourceState.CopyDest);
}
_directCmd.ResourceBarrier(bufferHandle, ResourceState.CopyDest);
_directCmd.UploadBuffer(meshData.ObjectDataBuffer, [data]);
if (needTransition)
{
_directCmd.ResourceBarrier(bufferHandle, ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
}
_directCmd.ResourceBarrier(bufferHandle, ResourceState.VertexAndConstantBuffer);
}
public Handle<Texture> CreateTexture<T>(ref readonly TextureDesc desc, ReadOnlySpan<T> data, bool tempResource = false)
@@ -191,15 +156,7 @@ public readonly unsafe ref struct RenderingContext
desc.TextureDescription.Format.GetSurfaceInfo(desc.TextureDescription.Width, desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource())
.GetValueOrThrow(ResultStatus.Success);
var needTransition = sateBefore != ResourceState.CopyDest;
if (needTransition)
{
_directCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
}
_directCmd.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest);
fixed (T* pData = data)
{
@@ -212,11 +169,6 @@ public readonly unsafe ref struct RenderingContext
_directCmd.UploadTexture(texture, [subresourceData]);
}
if (needTransition)
{
_directCmd.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
}
}
// TODO: Ideally we should queue the draw call to our rendering system, and render it in a full rendering pipeline.