fix(rt): make BuildTLAS's read barrier a memory dependency
BuildTLAS ended with an execution-only barrier from the acceleration-structure build to the ray-tracing and compute shader stages. That orders the commands, but without a memory barrier the build's writes are never made available and visible to the traceRayEXT and rayQueryEXT reads recorded after it in the same command buffer, which is the documented per-frame flow (BuildTLAS in onUpdate, then RTPass): the trace may read a stale or half-written BVH. The barrier now carries ACCELERATION_STRUCTURE_WRITE -> ACCELERATION_STRUCTURE_READ. BuildTlasReadBarrier builds it as pure CPU logic, so a test can check it without a GPU, as with the swapchain barriers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
dfb70bc088
commit
824436e67c
2 changed files with 25 additions and 9 deletions
|
|
@ -295,13 +295,6 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTB
|
||||||
VkAccelerationStructureBuildRangeInfoKHR* tlasRangeInfoPP = &tlasRangeInfo;
|
VkAccelerationStructureBuildRangeInfoKHR* tlasRangeInfoPP = &tlasRangeInfo;
|
||||||
Device::vkCmdBuildAccelerationStructuresKHR(cmd, 1, &tlasBuildGeometryInfo, &tlasRangeInfoPP);
|
Device::vkCmdBuildAccelerationStructuresKHR(cmd, 1, &tlasBuildGeometryInfo, &tlasRangeInfoPP);
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
const TlasReadBarrier readBarrier = BuildTlasReadBarrier();
|
||||||
cmd,
|
vkCmdPipelineBarrier(cmd, readBarrier.srcStage, readBarrier.dstStage, 0, 1, &readBarrier.memory, 0, nullptr, 0, nullptr);
|
||||||
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
||||||
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
||||||
0,
|
|
||||||
0, nullptr,
|
|
||||||
0, nullptr,
|
|
||||||
0, nullptr
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
@ -134,6 +134,29 @@ export namespace Crafter {
|
||||||
static void Add(RenderingElement3D* e);
|
static void Add(RenderingElement3D* e);
|
||||||
static void Remove(RenderingElement3D* e);
|
static void Remove(RenderingElement3D* e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The dependency BuildTLAS records after its build, ordering it before
|
||||||
|
// the shaders that read the TLAS later in the same command buffer:
|
||||||
|
// traceRayEXT in a ray-tracing pass, rayQueryEXT in a compute pass. It
|
||||||
|
// has to carry the acceleration-structure memory dependency; ordering
|
||||||
|
// execution alone never makes the build's writes visible to those reads.
|
||||||
|
struct TlasReadBarrier {
|
||||||
|
VkPipelineStageFlags srcStage;
|
||||||
|
VkPipelineStageFlags dstStage;
|
||||||
|
VkMemoryBarrier memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline TlasReadBarrier BuildTlasReadBarrier() {
|
||||||
|
return {
|
||||||
|
.srcStage = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
||||||
|
.dstStage = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
.memory = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||||
|
.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
|
||||||
|
.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue