Merge pull request 'perf(mesh): dirty-range vertex upload for deforming-mesh Refit (#119)' (#138) from claude/issue-119 into master

This commit is contained in:
catbot 2026-06-17 21:51:26 +02:00
commit e3edb87c0f
5 changed files with 199 additions and 8 deletions

View file

@ -157,6 +157,42 @@ int main() {
Check(tri.blasAddr == triAddrBefore,
"Refit kept the same blasAddr (instances stay valid)");
// Dirty-range refit (issue #119): move only a sub-window of the vertices
// and pass it as [offset, count). The ranged upload patches just those
// vertices in place; the UPDATE must still keep the same AS handle /
// blasAddr, and the validation layer (checked at the end) is the real proof
// that the ranged host-write / flush / barrier — and the staged variant
// below — are spec-correct. The untouched vertices retain their last values
// in the device buffer, so the refit BLAS is over the full deformed cube.
{
// Full array of moved positions; we declare only the back half [4,8)
// as the dirty window, so only those 4 vertices are re-uploaded.
auto verts = CubeVerts(2.0f);
auto idx = CubeIndices();
VkCommandBuffer cmd = BeginCmd();
tri.Refit(verts, idx, /*dirtyVertexOffset*/ 4, /*dirtyVertexCount*/ 4, cmd);
SubmitWait(cmd);
}
Check(tri.accelerationStructure == triHandleBefore,
"dirty-range Refit kept the same AS handle (in-place UPDATE, #119)");
Check(tri.blasAddr == triAddrBefore,
"dirty-range Refit kept the same blasAddr (#119)");
// A dirty-range refit on a mesh whose counts changed must still fall back
// to a full rebuild (the dirty window is irrelevant on that path) and
// succeed — same robustness as the full-span Refit fallback.
{
auto verts = CubeVerts(1.0f);
verts.push_back({2.0f, 2.0f, 2.0f}); // count change → topology change
auto idx = CubeIndices();
idx.insert(idx.end(), {0u, 1u, 8u});
VkCommandBuffer cmd = BeginCmd();
tri.Refit(verts, idx, /*dirtyVertexOffset*/ 8, /*dirtyVertexCount*/ 1, cmd);
SubmitWait(cmd);
}
Check(tri.blasAddr != 0 && tri.builtPrimitiveCount == 13,
"dirty-range Refit with a count change rebuilt the BLAS (13 prims, #119)");
// ── Triangle BLAS: fast-build, no update → flags reflect the choice. ─
Mesh triFast;
{
@ -340,6 +376,19 @@ int main() {
Check(staged.accelerationStructure == stagedHandle,
"staged-upload Refit kept the same AS handle (in-place UPDATE, #73)");
// Dirty-range refit on the staged path (#119): the ranged upload must
// take the stage-a-sub-slice + vkCmdCopyBuffer-at-offset path (the
// buffer is pure DEVICE_LOCAL), keep the AS handle, and stay
// validation-clean. Only the front half [0,4) is declared dirty.
{
auto verts3 = CubeVerts(2.0f);
VkCommandBuffer cmd = BeginCmd();
staged.Refit(verts3, idx, /*dirtyVertexOffset*/ 0, /*dirtyVertexCount*/ 4, cmd);
SubmitWait(cmd);
}
Check(staged.accelerationStructure == stagedHandle,
"staged-upload dirty-range Refit kept the same AS handle (#119)");
Device::directWriteBudget = savedBudget;
}