2 changed files with 41 additions and 10 deletions
test+usage: device-local geometry readback + isolate #67 staging count
- Add TRANSFER_SRC to RT geometry usage so device-local geometry (now in VRAM, no longer host-mappable) stays copyable/inspectable. - MeshDecompressStagingRelease: read decompressed vertex/index back via a device->host copy instead of the removed host-mapped .value/FlushHost, and build the mesh with allowUpdate=true so the retained per-mesh scratch (#66) doesn't also land in the deletion queue — isolating the assertion to the released compressed staging (#67). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
commit
ed9b3f67a7
|
|
@ -32,10 +32,16 @@ using namespace Crafter;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Buffer-usage flag set shared by both Build paths. The compressed path
|
// Buffer-usage flag set shared by both Build paths. The compressed path
|
||||||
// appends VK_BUFFER_USAGE_2_MEMORY_DECOMPRESSION_BIT_EXT.
|
// appends VK_BUFFER_USAGE_2_MEMORY_DECOMPRESSION_BIT_EXT, and the staged
|
||||||
|
// upload path appends VK_BUFFER_USAGE_TRANSFER_DST_BIT. TRANSFER_SRC is in
|
||||||
|
// the base because the geometry is now device-local (#73): once it no longer
|
||||||
|
// lives in host-mappable memory, a transfer copy is the only way to read it
|
||||||
|
// back (debugging, GPU-driven workflows, decompression validation) — a free
|
||||||
|
// usage flag that keeps device-local geometry inspectable.
|
||||||
constexpr VkBufferUsageFlags2 kVertexUsageBase =
|
constexpr VkBufferUsageFlags2 kVertexUsageBase =
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
| VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
| VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR
|
||||||
|
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
constexpr VkBufferUsageFlags2 kIndexUsageBase =
|
constexpr VkBufferUsageFlags2 kIndexUsageBase =
|
||||||
kVertexUsageBase | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
kVertexUsageBase | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,13 @@ int main() {
|
||||||
|
|
||||||
Mesh mesh;
|
Mesh mesh;
|
||||||
VkCommandBuffer cmd = BeginCmd();
|
VkCommandBuffer cmd = BeginCmd();
|
||||||
mesh.Build(asset, cmd);
|
// allowUpdate=true so the per-mesh BLAS scratch is RETAINED for refit
|
||||||
|
// (issue #66) rather than deferred-cleared after the build. A static
|
||||||
|
// (allowUpdate=false) build would also hand its scratch to the deletion
|
||||||
|
// queue, making the count below 2; keeping it isolates this test to the
|
||||||
|
// one allocation it cares about — the released compressed staging (#67).
|
||||||
|
// The staging-release behavior under test is independent of allowUpdate.
|
||||||
|
mesh.Build(asset, cmd, RTBuildOptions{ .allowUpdate = true });
|
||||||
|
|
||||||
// ── The fix: staging is released to the queue at record time, not pinned. ──
|
// ── The fix: staging is released to the queue at record time, not pinned. ──
|
||||||
Check(mesh.compressedStaging.buffer == VK_NULL_HANDLE,
|
Check(mesh.compressedStaging.buffer == VK_NULL_HANDLE,
|
||||||
|
|
@ -168,16 +174,35 @@ int main() {
|
||||||
Check(Device::validationErrorCount == 0,
|
Check(Device::validationErrorCount == 0,
|
||||||
"decompress + BLAS build raised no validation errors");
|
"decompress + BLAS build raised no validation errors");
|
||||||
|
|
||||||
// The GPU decompress wrote into the host-visible vertex/index buffers;
|
// The GPU decompress wrote into the device-local vertex/index buffers
|
||||||
// invalidate and read them back — releasing the staging must not corrupt
|
// (issue #73 placed RT geometry in VRAM, so they are no longer host-mapped).
|
||||||
// the decompressed result.
|
// Copy them back to host-visible staging — the proper way to inspect
|
||||||
mesh.vertexBuffer.FlushHost();
|
// device-local memory — and compare: releasing the compressed staging must
|
||||||
mesh.indexBuffer.FlushHost();
|
// not have corrupted the decompressed result. The geometry buffers carry
|
||||||
|
// TRANSFER_SRC for exactly this (#73).
|
||||||
|
VulkanBuffer<Vector<float, 3, 3>, true> vertReadback;
|
||||||
|
VulkanBuffer<std::uint32_t, true> idxReadback;
|
||||||
|
vertReadback.Resize(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, static_cast<std::uint32_t>(srcMesh.vertexes.size()));
|
||||||
|
idxReadback.Resize(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, static_cast<std::uint32_t>(srcMesh.indexes.size()));
|
||||||
|
{
|
||||||
|
// Safe to copy without a barrier: SubmitWait above wait-idled the queue,
|
||||||
|
// so the decompress + BLAS reads of these buffers have fully retired.
|
||||||
|
VkCommandBuffer rcmd = BeginCmd();
|
||||||
|
VkBufferCopy vRegion { .srcOffset = 0, .dstOffset = 0, .size = vertReadback.size };
|
||||||
|
vkCmdCopyBuffer(rcmd, mesh.vertexBuffer.buffer, vertReadback.buffer, 1, &vRegion);
|
||||||
|
VkBufferCopy iRegion { .srcOffset = 0, .dstOffset = 0, .size = idxReadback.size };
|
||||||
|
vkCmdCopyBuffer(rcmd, mesh.indexBuffer.buffer, idxReadback.buffer, 1, &iRegion);
|
||||||
|
SubmitWait(rcmd);
|
||||||
|
}
|
||||||
|
vertReadback.FlushHost();
|
||||||
|
idxReadback.FlushHost();
|
||||||
const bool vertsMatch = std::memcmp(
|
const bool vertsMatch = std::memcmp(
|
||||||
mesh.vertexBuffer.value, srcMesh.vertexes.data(),
|
vertReadback.value, srcMesh.vertexes.data(),
|
||||||
srcMesh.vertexes.size() * sizeof(srcMesh.vertexes[0])) == 0;
|
srcMesh.vertexes.size() * sizeof(srcMesh.vertexes[0])) == 0;
|
||||||
const bool idxMatch = std::memcmp(
|
const bool idxMatch = std::memcmp(
|
||||||
mesh.indexBuffer.value, srcMesh.indexes.data(),
|
idxReadback.value, srcMesh.indexes.data(),
|
||||||
srcMesh.indexes.size() * sizeof(srcMesh.indexes[0])) == 0;
|
srcMesh.indexes.size() * sizeof(srcMesh.indexes[0])) == 0;
|
||||||
Check(vertsMatch, "GPU-decompressed vertices are byte-equal to the source");
|
Check(vertsMatch, "GPU-decompressed vertices are byte-equal to the source");
|
||||||
Check(idxMatch, "GPU-decompressed indices are byte-equal to the source");
|
Check(idxMatch, "GPU-decompressed indices are byte-equal to the source");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue