Refactor RenderGraph barrier/state tracking system

Major overhaul of resource barrier and state tracking in RenderGraph:
- Introduce ResourceBarrierData for explicit (layout, access, sync) tracking.
- Separate aliasing and transition barriers; explicit aliasing support.
- Remove BufferHint; infer buffer usage from BufferUsage flags.
- Update TextureAccess/BufferAccess to include usage requirements.
- Improve enums (BarrierSync, BarrierAccess, BarrierLayout) for D3D12 alignment.
- Update D3D12CommandBuffer to use new barrier data and error handling.
- Make D3D12DescriptorHeap a class; add ReleaseSampler to IResourceDatabase.
- Reset resource pools and aliasing managers each frame.
- Batch and flush barriers efficiently per pass.
- Update HLSL mesh shader macros to [NumThreads].
- Remove obsolete code and improve documentation.
This refactor improves correctness, extensibility, and prepares for advanced features.
This commit is contained in:
2026-01-22 20:51:58 +09:00
parent 139312d73b
commit 4173ff2432
18 changed files with 395 additions and 488 deletions

View File

@@ -248,7 +248,15 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
break;
case BarrierType.Buffer:
{
var resource = _resourceDatabase.GetResource(desc.Resource);
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
if (r.IsFailure)
{
RecordError(nameof(ResourceBarrier), r.Error);
continue;
}
ref var record = ref r.Value;
var resource = record.ResourcePtr;
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
{
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
@@ -259,11 +267,21 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
Offset = 0,
Size = ulong.MaxValue
};
record.barrierData = new ResourceBarrierData(BarrierLayout.Undefined, desc.AccessAfter, desc.SyncAfter);
}
break;
case BarrierType.Texture:
{
var resource = _resourceDatabase.GetResource(desc.Resource);
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
if (r.IsFailure)
{
RecordError(nameof(ResourceBarrier), r.Error);
continue;
}
ref var record = ref r.Value;
var resource = record.ResourcePtr;
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
{
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
@@ -282,6 +300,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
},
Flags = desc.Discard ? D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_NONE
};
record.barrierData = new ResourceBarrierData(desc.LayoutAfter, desc.AccessAfter, desc.SyncAfter);
}
break;
}

View File

@@ -10,7 +10,7 @@ using static TerraFX.Aliases.D3D12_Alias;
namespace Ghost.Graphics.D3D12;
internal unsafe struct D3D12DescriptorHeap : IDisposable
internal unsafe class D3D12DescriptorHeap : IDisposable
{
private const int _INVALID_DESCRIPTOR_INDEX = -1;
@@ -51,8 +51,8 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
get;
}
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
public ID3D12DescriptorHeap* Heap => _heap.Get();
public ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
public D3D12DescriptorHeap(string name, D3D12RenderDevice device, D3D12_DESCRIPTOR_HEAP_TYPE type, int numDescriptors)
{
@@ -164,17 +164,18 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
}
}
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int index)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int index)
{
if (index < 0 || index >= NumDescriptors)
{
throw new ArgumentOutOfRangeException(nameof(index), "Descriptor index is out of range.");
}
return _startCpuHandle.Offset(index, Stride);
var handle = _startCpuHandle;
return handle.Offset(index, Stride);
}
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(int index)
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(int index)
{
if (index < 0 || index >= NumDescriptors)
{
@@ -186,10 +187,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
throw new InvalidOperationException("Descriptor heap is not shader visible.");
}
return _startCpuHandleShaderVisible.Offset(index, Stride);
var handle = _startCpuHandleShaderVisible;
return handle.Offset(index, Stride);
}
public readonly D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int index)
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int index)
{
if (index < 0 || index >= NumDescriptors)
{
@@ -201,10 +203,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
throw new InvalidOperationException("Descriptor heap is not shader visible.");
}
return _startGpuHandleShaderVisible.Offset(index, Stride);
var handle = _startGpuHandleShaderVisible;
return handle.Offset(index, Stride);
}
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
public void CopyToShaderVisibleHeap(int index, int count = 1)
{
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
}

View File

@@ -323,6 +323,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return _samplers.TryGetValue(desc, out id);
}
public void ReleaseSampler(Identifier<Sampler> id)
{
ObjectDisposedException.ThrowIf(_disposed, this);
// NOTE: We almost never release samplers individually, because they are cheap and can be reused.
// Ideally we would release all samplers at once when disposing the ResourceDatabase.
_descriptorAllocator.Release(new Identifier<SamplerDescriptor>(id.Value));
}
public Handle<Mesh> AddMesh(ref readonly Mesh mesh)
{
ObjectDisposedException.ThrowIf(_disposed, this);

View File

@@ -149,7 +149,8 @@ internal unsafe class D3D12SwapChain : ISwapChain
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
var rtv = _descriptorAllocator.AllocateRTV();
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
var cpuHandle = _descriptorAllocator.GetCpuHandle(rtv);
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, cpuHandle);
var view = ResourceViewGroup.Invalid with
{