Enhanced barrier

This commit is contained in:
2026-01-22 12:33:23 +09:00
parent 92b966fe0d
commit 139312d73b
35 changed files with 653 additions and 9544 deletions

View File

@@ -744,11 +744,23 @@ public sealed class RenderGraph : IDisposable
// If we found a previous resource, insert aliasing barrier
if (mostRecentLastUse >= 0)
{
var barrier = ResourceBarrier.CreateAliasingBarrier(
resourceBefore,
id,
passIdx
);
BarrierDesc desc;
if (resource.type == RenderGraphResourceType.Texture)
{
desc = BarrierDesc.Texture(resource.backingResource,
BarrierSync.All, BarrierSync.None,
BarrierAccess.NoAccess, BarrierAccess.NoAccess,
BarrierLayout.Undefined, BarrierLayout.Common,
discard: true);
}
else
{
desc = BarrierDesc.Buffer(resource.backingResource,
BarrierSync.All, BarrierSync.None,
BarrierAccess.NoAccess, BarrierAccess.NoAccess);
}
var barrier = ResourceBarrier.Create(passIdx, desc, id);
_barriers.Add(barrier);
}
}
@@ -843,17 +855,120 @@ public sealed class RenderGraph : IDisposable
if (currentState != newState)
{
var barrier = ResourceBarrier.CreateTransitionBarrier(
resource,
currentState,
newState,
passIdx
);
var res = _resources.GetResource(resource);
GetBarrierInfo(currentState, out var syncBefore, out var accessBefore, out var layoutBefore);
GetBarrierInfo(newState, out var syncAfter, out var accessAfter, out var layoutAfter);
BarrierDesc desc;
if (res.type == RenderGraphResourceType.Texture)
{
desc = BarrierDesc.Texture(res.backingResource,
syncBefore, syncAfter,
accessBefore, accessAfter,
layoutBefore, layoutAfter);
}
else
{
desc = BarrierDesc.Buffer(res.backingResource,
syncBefore, syncAfter,
accessBefore, accessAfter);
}
var barrier = ResourceBarrier.Create(passIdx, desc, resource);
_barriers.Add(barrier);
_resourceStates[resource.Value] = newState;
}
}
private static void GetBarrierInfo(ResourceState state, out BarrierSync sync, out BarrierAccess access, out BarrierLayout layout)
{
sync = BarrierSync.None;
access = BarrierAccess.Common;
layout = BarrierLayout.Common;
if (state == ResourceState.Common)
{
return;
}
if (state.HasFlag(ResourceState.RenderTarget))
{
sync |= BarrierSync.RenderTarget;
access |= BarrierAccess.RenderTarget;
layout = BarrierLayout.RenderTarget;
}
if (state.HasFlag(ResourceState.DepthWrite))
{
sync |= BarrierSync.DepthStencil;
access |= BarrierAccess.DepthStencilWrite;
layout = BarrierLayout.DepthStencilWrite;
}
if (state.HasFlag(ResourceState.DepthRead))
{
sync |= BarrierSync.DepthStencil;
access |= BarrierAccess.DepthStencilRead;
layout = BarrierLayout.DepthStencilRead;
}
if (state.HasFlag(ResourceState.UnorderedAccess))
{
sync |= BarrierSync.AllShading;
access |= BarrierAccess.UnorderedAccess;
layout = BarrierLayout.UnorderedAccess;
}
if (state.HasFlag(ResourceState.PixelShaderResource))
{
sync |= BarrierSync.PixelShading;
access |= BarrierAccess.ShaderResource;
layout = BarrierLayout.ShaderResource;
}
if (state.HasFlag(ResourceState.NonPixelShaderResource))
{
sync |= BarrierSync.NonPixelShading;
access |= BarrierAccess.ShaderResource;
layout = BarrierLayout.ShaderResource;
}
if (state.HasFlag(ResourceState.CopyDest))
{
sync |= BarrierSync.Copy;
access |= BarrierAccess.CopyDest;
layout = BarrierLayout.CopyDest;
}
if (state.HasFlag(ResourceState.CopySource))
{
sync |= BarrierSync.Copy;
access |= BarrierAccess.CopySource;
layout = BarrierLayout.CopySource;
}
if (state.HasFlag(ResourceState.VertexAndConstantBuffer))
{
sync |= BarrierSync.VertexShading;
access |= BarrierAccess.VertexBuffer | BarrierAccess.ConstantBuffer;
layout = BarrierLayout.Common;
}
if (state.HasFlag(ResourceState.IndexBuffer))
{
sync |= BarrierSync.IndexInput;
access |= BarrierAccess.IndexBuffer;
layout = BarrierLayout.Common;
}
if (state.HasFlag(ResourceState.IndirectArgument))
{
sync |= BarrierSync.ExecuteIndirect;
access |= BarrierAccess.IndirectArgument;
layout = BarrierLayout.GenericRead;
}
if (state.HasFlag(ResourceState.GenericRead))
{
layout = BarrierLayout.GenericRead;
}
if (state.HasFlag(ResourceState.Present))
{
sync = BarrierSync.All;
access = BarrierAccess.Common;
layout = BarrierLayout.Present;
}
}
/// <summary>
/// Determines the appropriate resource state for a buffer read operation based on usage hints.
/// </summary>
@@ -1327,55 +1442,30 @@ public sealed class RenderGraph : IDisposable
/// </summary>
private unsafe void ExecuteBarriersForPass(ICommandBuffer cmd, int passIndex, ref int barrierIndex)
{
var pBarrierDescs = stackalloc BarrierDesc[16]; // batch by 16
var count = 0;
var hasRemain = false;
int start = barrierIndex;
int count = 0;
Start:
while (barrierIndex < _barriers.Count && _barriers[barrierIndex].PassIndex == passIndex)
{
var barrier = _barriers[barrierIndex];
var desc = new BarrierDesc();
desc.type = barrier.Type;
switch (desc.type)
{
case BarrierType.Transition:
desc.transition.resource = _resources.GetResource(barrier.Resource).backingResource;
desc.transition.stateBefore = barrier.StateBefore;
desc.transition.stateAfter = barrier.StateAfter;
break;
case BarrierType.Aliasing:
desc.aliasing.resourceBefore = _resources.GetResource(barrier.ResourceBefore).backingResource;
desc.aliasing.resourceAfter = _resources.GetResource(barrier.ResourceAfter).backingResource;
break;
case BarrierType.UAV:
desc.uav.resource = _resources.GetResource(barrier.Resource).backingResource;
break;
}
pBarrierDescs[count] = desc;
count++;
barrierIndex++;
if (count == 16)
{
hasRemain = _barriers.Count > barrierIndex && _barriers[barrierIndex].PassIndex == passIndex;
break;
}
}
if (count > 0)
{
cmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(pBarrierDescs, count));
}
if (hasRemain)
{
count = 0;
hasRemain = false;
goto Start;
const int BatchSize = 64;
var descs = stackalloc BarrierDesc[BatchSize];
int processed = 0;
while (processed < count)
{
int batch = Math.Min(count - processed, BatchSize);
for (int i = 0; i < batch; i++)
{
descs[i] = _barriers[start + processed + i].Desc;
}
cmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(descs, batch));
processed += batch;
}
}
}

View File

@@ -6,95 +6,22 @@ namespace Ghost.Graphics.RenderGraphModule;
/// <summary>
/// Represents a resource barrier that needs to be inserted.
/// For D3D12 aliasing barriers: ResourceBefore is the old resource, ResourceAfter is the new resource.
/// </summary>
internal struct ResourceBarrier
{
[StructLayout(LayoutKind.Explicit)]
private struct barrier_union
{
internal struct barrier_union_transition
{
public Identifier<RGResource> resource;
public ResourceState stateBefore;
public ResourceState stateAfter;
}
public int PassIndex;
public BarrierDesc Desc;
public Identifier<RGResource> LogicalResource;
internal struct barrier_union_aliasing
{
public Identifier<RGResource> resourceBefore;
public Identifier<RGResource> resourceAfter;
}
public readonly Identifier<RGResource> Resource => LogicalResource;
// TODO: union can not have non-blittable types
[FieldOffset(0)]
public barrier_union_transition transition;
[FieldOffset(0)]
public barrier_union_aliasing aliasing;
}
private barrier_union _union;
public BarrierType Type
{
get; init;
}
public int PassIndex
{
get; init;
}
// For Transition and UAV barriers
public readonly Identifier<RGResource> Resource => _union.transition.resource;
public readonly ResourceState StateBefore => _union.transition.stateBefore;
public readonly ResourceState StateAfter => _union.transition.stateAfter;
// For Aliasing barriers (D3D12_RESOURCE_BARRIER::Aliasing)
public readonly Identifier<RGResource> ResourceBefore => _union.aliasing.resourceBefore;
public readonly Identifier<RGResource> ResourceAfter => _union.aliasing.resourceAfter;
// Constructor for Aliasing barriers
public static ResourceBarrier CreateAliasingBarrier(
Identifier<RGResource> resourceBefore,
Identifier<RGResource> resourceAfter,
int passIndex)
public static ResourceBarrier Create(int passIndex, BarrierDesc desc, Identifier<RGResource> logicalResource)
{
return new ResourceBarrier
{
Type = BarrierType.Aliasing,
PassIndex = passIndex,
_union = new barrier_union
{
aliasing = new barrier_union.barrier_union_aliasing
{
resourceBefore = resourceBefore,
resourceAfter = resourceAfter
}
}
};
}
public static ResourceBarrier CreateTransitionBarrier(
Identifier<RGResource> resource,
ResourceState before,
ResourceState after,
int passIndex)
{
return new ResourceBarrier
{
Type = BarrierType.Transition,
PassIndex = passIndex,
_union = new barrier_union
{
transition = new barrier_union.barrier_union_transition
{
resource = resource,
stateBefore = before,
stateAfter = after
}
}
Desc = desc,
LogicalResource = logicalResource
};
}
}