feat(rt): BuildProcedural/RefitProcedural from a device AABB buffer (#37)
Add zero-copy procedural BLAS overloads that take the AABB build input straight from an existing device buffer instead of memcpy-ing a host span through Mesh::aabbBuffer — the input-source companion to #36's refit work. A GPU compute producer (e.g. a GPU-resident particle system) can now feed a moving procedural BLAS that builds/refits each frame with no host round-trip. Vulkan: new BuildProcedural(VkDeviceAddress, count, ...) and RefitProcedural(VkDeviceAddress, count, ...) feed the device address directly into VkAccelerationStructureGeometryAabbsDataKHR; the host-span path is refactored to share RecordProceduralBuildFromAddress and is otherwise unchanged. WebGPU: device-buffer BuildProcedural/RefitProcedural copy the boxes GPU->GPU into the mesh heap (new wgpuRegisterMeshBLASDeviceAabbs / wgpuRefitMeshBLAS- DeviceAabbs bridge fns) and wrap them in a single root leaf bounded by a caller-supplied worldBounds — no wasm round-trip, blasAddr stable across refit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
00d14d67cb
commit
f14441942a
5 changed files with 306 additions and 21 deletions
|
|
@ -125,6 +125,23 @@ export namespace Crafter {
|
|||
// exactly like a triangle BLAS.
|
||||
void BuildProcedural(std::span<const RTAabb> aabbs, bool opaque, VkCommandBuffer cmd, RTBuildOptions options = {});
|
||||
|
||||
// Zero-copy procedural build: take the AABB build input straight from
|
||||
// an existing device buffer (by device address + primitive count)
|
||||
// rather than memcpy-ing a host span through aabbBuffer. The intended
|
||||
// producer is a GPU compute pass that writes the boxes itself — e.g.
|
||||
// a GPU-resident particle system whose per-frame AABBs never touch the
|
||||
// CPU. The buffer must carry
|
||||
// VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR
|
||||
// and VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, its boxes laid out as
|
||||
// VkAabbPositionsKHR (`stride`, default sizeof(RTAabb) == 24), and the
|
||||
// caller must pipeline-barrier the producing writes (e.g. a compute
|
||||
// dispatch) before the build on `cmd` reads them. The buffer's
|
||||
// lifetime is the caller's responsibility — it is never copied, so it
|
||||
// must outlive the build submitted on `cmd`. Everything else (opaque
|
||||
// bit, hit-group contract, instance wiring) matches the host-span
|
||||
// BuildProcedural above.
|
||||
void BuildProcedural(VkDeviceAddress aabbAddress, std::uint32_t count, bool opaque, VkCommandBuffer cmd, RTBuildOptions options = {}, std::uint32_t stride = sizeof(RTAabb));
|
||||
|
||||
// Refit the triangle BLAS against new geometry of the *same
|
||||
// topology* (same vertex count and index count as the original
|
||||
// Build). When that Build set RTBuildOptions::allowUpdate this issues
|
||||
|
|
@ -139,6 +156,16 @@ export namespace Crafter {
|
|||
void Refit(std::span<Vector<float, 3, 3>> verticies, std::span<std::uint32_t> indicies, VkCommandBuffer cmd);
|
||||
// Procedural analog of Refit: new object-space boxes, same count.
|
||||
void RefitProcedural(std::span<const RTAabb> aabbs, VkCommandBuffer cmd);
|
||||
// Zero-copy procedural refit: the device-buffer counterpart of
|
||||
// RefitProcedural above and the input-source pairing for the device
|
||||
// BuildProcedural. The GPU producer rewrote the boxes in `aabbAddress`
|
||||
// in place; this re-records the build straight from that address —
|
||||
// an in-place hardware UPDATE when the original build set allowUpdate
|
||||
// and `count` is unchanged (handle / blasAddr preserved), otherwise a
|
||||
// full rebuild. Same buffer-usage / barrier / lifetime contract as the
|
||||
// device BuildProcedural. Call per frame to track GPU-written boxes
|
||||
// with zero host involvement.
|
||||
void RefitProcedural(VkDeviceAddress aabbAddress, std::uint32_t count, VkCommandBuffer cmd, std::uint32_t stride = sizeof(RTAabb));
|
||||
};
|
||||
}
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
@ -243,6 +270,25 @@ export namespace Crafter {
|
|||
WebGPUCommandEncoderRef cmd = 0,
|
||||
RTBuildOptions options = {});
|
||||
|
||||
// Zero-copy procedural build: the boxes already live in an existing
|
||||
// device buffer (`aabbBuffer`, a GPUBuffer a compute pass wrote), fed
|
||||
// straight into the BLAS with no host copy — the WebGPU analog of the
|
||||
// device-address Vulkan BuildProcedural. The software path has no
|
||||
// hardware AS and builds its BVH on the host, but here there is no
|
||||
// host copy to build over, so the device boxes are copied GPU→GPU into
|
||||
// the mesh heap and wrapped in a single root leaf bounded by
|
||||
// `worldBounds` (object-space min/max enclosing all `count` boxes —
|
||||
// the producer supplies it since the CPU never sees the boxes). The
|
||||
// traversal then linearly intersects every box. `opaque` is the
|
||||
// geometry opaque bit (false lets any-hit run). `options` has no effect
|
||||
// (no hardware AS to tune), kept for API symmetry.
|
||||
void BuildProcedural(WebGPUBufferRef aabbBuffer,
|
||||
std::uint32_t count,
|
||||
RTAabb worldBounds,
|
||||
bool opaque = false,
|
||||
WebGPUCommandEncoderRef cmd = 0,
|
||||
RTBuildOptions options = {});
|
||||
|
||||
// Refit analogs of the native API. With no hardware AS to update,
|
||||
// these simply re-run the host BVH build over the new data, so they
|
||||
// accept the full geometry (not just moved positions). Provided so
|
||||
|
|
@ -253,6 +299,16 @@ export namespace Crafter {
|
|||
WebGPUCommandEncoderRef cmd = 0);
|
||||
void RefitProcedural(std::span<const RTAabb> aabbs,
|
||||
WebGPUCommandEncoderRef cmd = 0);
|
||||
// Zero-copy procedural refit: re-copy the boxes from the device buffer
|
||||
// into this mesh's heap region (count unchanged) and update the root
|
||||
// leaf bounds, keeping blasAddr stable — unlike the host-span
|
||||
// RefitProcedural, which rebuilds and re-publishes a NEW handle. The
|
||||
// device counterpart of the device-address Vulkan RefitProcedural;
|
||||
// call per frame to track GPU-written boxes with no host copy.
|
||||
void RefitProcedural(WebGPUBufferRef aabbBuffer,
|
||||
std::uint32_t count,
|
||||
RTAabb worldBounds,
|
||||
WebGPUCommandEncoderRef cmd = 0);
|
||||
};
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue