test(vulkan): publish readback before host mapping
Record the exact sync2 COPY/TRANSFER_WRITE to HOST/HOST_READ buffer dependency over the copied readback range before ending and submitting the existing command buffer. Preserve coherent mapping and queue-idle completion. Add a portable guard that inspects the descriptor factory used by the live ReadBack path and pins copy, descriptor, barrier, end, and submit order without initializing Vulkan. Mutations performed and restored: 1. Removed the live post-copy barrier: the guard first failed with Expected copy -> descriptor -> barrier -> end -> submit, got 4260, -1, -1, -1, 4386, 4900. 2. Changed source access to TransferReadBit: the guard first failed Assert.Equal, expected Access2TransferWriteBit, actual Access2TransferReadBit. 3. Moved the correct barrier before the copy: the guard first failed with Expected copy -> descriptor -> barrier -> end -> submit, got 4657, 4260, 4525, 4594, 4783, 5297.
This commit is contained in:
parent
7506e5f14e
commit
b333edb4f2
1 changed files with 64 additions and 0 deletions
|
|
@ -43,6 +43,44 @@ public sealed unsafe class MeshModernSharedIndexOffscreenTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReadbackDependency_PublishesTheExactCopiedRangeBeforeEndAndSubmit()
|
||||||
|
{
|
||||||
|
const ulong byteCount = 16_384;
|
||||||
|
var readback = new Buffer(0x470u);
|
||||||
|
|
||||||
|
BufferMemoryBarrier2 barrier = CreateHostReadBarrier(readback, byteCount);
|
||||||
|
Assert.Equal(StructureType.BufferMemoryBarrier2, barrier.SType);
|
||||||
|
Assert.Equal(PipelineStageFlags2.CopyBit, barrier.SrcStageMask);
|
||||||
|
Assert.Equal(AccessFlags2.TransferWriteBit, barrier.SrcAccessMask);
|
||||||
|
Assert.Equal(PipelineStageFlags2.HostBit, barrier.DstStageMask);
|
||||||
|
Assert.Equal(AccessFlags2.HostReadBit, barrier.DstAccessMask);
|
||||||
|
Assert.Equal(Silk.NET.Vulkan.Vk.QueueFamilyIgnored, barrier.SrcQueueFamilyIndex);
|
||||||
|
Assert.Equal(Silk.NET.Vulkan.Vk.QueueFamilyIgnored, barrier.DstQueueFamilyIndex);
|
||||||
|
Assert.Equal(readback.Handle, barrier.Buffer.Handle);
|
||||||
|
Assert.Equal(0ul, barrier.Offset);
|
||||||
|
Assert.Equal(byteCount, barrier.Size);
|
||||||
|
|
||||||
|
string source = File.ReadAllText(Path.Combine(
|
||||||
|
RepositoryRoot(), "tests", "AcDream.App.Tests", "Rendering", "Gpu", "Vk",
|
||||||
|
"MeshModernSharedIndexOffscreenTests.cs"));
|
||||||
|
int readbackStart = source.LastIndexOf("private static byte[] ReadBack(", StringComparison.Ordinal);
|
||||||
|
int readbackEnd = source.LastIndexOf("private static int CountPixels(", StringComparison.Ordinal);
|
||||||
|
Assert.True(readbackStart >= 0 && readbackEnd > readbackStart);
|
||||||
|
string livePath = source[readbackStart..readbackEnd];
|
||||||
|
|
||||||
|
int copy = livePath.IndexOf("vk.CmdCopyImageToBuffer(commands, image, ImageLayout.TransferSrcOptimal, readback, 1, ©);", StringComparison.Ordinal);
|
||||||
|
int descriptor = livePath.IndexOf("BufferMemoryBarrier2 hostReadBarrier = CreateHostReadBarrier(readback, byteCount);", StringComparison.Ordinal);
|
||||||
|
int dependency = livePath.IndexOf("PBufferMemoryBarriers = &hostReadBarrier", StringComparison.Ordinal);
|
||||||
|
int publish = livePath.IndexOf("vk.CmdPipelineBarrier2(commands, &hostDependency);", StringComparison.Ordinal);
|
||||||
|
int end = livePath.IndexOf("vk.EndCommandBuffer(commands)", StringComparison.Ordinal);
|
||||||
|
int submit = livePath.IndexOf("vk.QueueSubmit2(queue, 1, &submit, default)", StringComparison.Ordinal);
|
||||||
|
Assert.True(
|
||||||
|
copy >= 0 && copy < descriptor && descriptor < dependency && dependency < publish
|
||||||
|
&& publish < end && end < submit,
|
||||||
|
$"Expected copy -> descriptor -> barrier -> end -> submit, got {copy}, {descriptor}, {dependency}, {publish}, {end}, {submit}.");
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] Render(
|
private static byte[] Render(
|
||||||
VulkanGpuDevice device,
|
VulkanGpuDevice device,
|
||||||
Silk.NET.Vulkan.Vk vk,
|
Silk.NET.Vulkan.Vk vk,
|
||||||
|
|
@ -264,6 +302,14 @@ public sealed unsafe class MeshModernSharedIndexOffscreenTests
|
||||||
ImageExtent = new Extent3D(Extent, Extent, 1),
|
ImageExtent = new Extent3D(Extent, Extent, 1),
|
||||||
};
|
};
|
||||||
vk.CmdCopyImageToBuffer(commands, image, ImageLayout.TransferSrcOptimal, readback, 1, ©);
|
vk.CmdCopyImageToBuffer(commands, image, ImageLayout.TransferSrcOptimal, readback, 1, ©);
|
||||||
|
BufferMemoryBarrier2 hostReadBarrier = CreateHostReadBarrier(readback, byteCount);
|
||||||
|
var hostDependency = new DependencyInfo
|
||||||
|
{
|
||||||
|
SType = StructureType.DependencyInfo,
|
||||||
|
BufferMemoryBarrierCount = 1,
|
||||||
|
PBufferMemoryBarriers = &hostReadBarrier,
|
||||||
|
};
|
||||||
|
vk.CmdPipelineBarrier2(commands, &hostDependency);
|
||||||
VulkanInterop.Check(vk.EndCommandBuffer(commands), "vkEndCommandBuffer (S5-470 readback)");
|
VulkanInterop.Check(vk.EndCommandBuffer(commands), "vkEndCommandBuffer (S5-470 readback)");
|
||||||
|
|
||||||
var commandInfo = new CommandBufferSubmitInfo
|
var commandInfo = new CommandBufferSubmitInfo
|
||||||
|
|
@ -304,6 +350,24 @@ public sealed unsafe class MeshModernSharedIndexOffscreenTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BufferMemoryBarrier2 CreateHostReadBarrier(Buffer readback, ulong byteCount)
|
||||||
|
{
|
||||||
|
ArgumentOutOfRangeException.ThrowIfZero(byteCount);
|
||||||
|
return new BufferMemoryBarrier2
|
||||||
|
{
|
||||||
|
SType = StructureType.BufferMemoryBarrier2,
|
||||||
|
SrcStageMask = PipelineStageFlags2.CopyBit,
|
||||||
|
SrcAccessMask = AccessFlags2.TransferWriteBit,
|
||||||
|
DstStageMask = PipelineStageFlags2.HostBit,
|
||||||
|
DstAccessMask = AccessFlags2.HostReadBit,
|
||||||
|
SrcQueueFamilyIndex = Silk.NET.Vulkan.Vk.QueueFamilyIgnored,
|
||||||
|
DstQueueFamilyIndex = Silk.NET.Vulkan.Vk.QueueFamilyIgnored,
|
||||||
|
Buffer = readback,
|
||||||
|
Offset = 0,
|
||||||
|
Size = byteCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static int CountPixels(ReadOnlySpan<byte> pixels, byte expected)
|
private static int CountPixels(ReadOnlySpan<byte> pixels, byte expected)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue