tlas build options
This commit is contained in:
parent
e3940d99c3
commit
00d14d67cb
3 changed files with 50 additions and 13 deletions
|
|
@ -188,7 +188,9 @@ void RenderingElement3D::BuildTLASBuild(WebGPUCommandEncoderRef /*cmd*/, std::ui
|
||||||
tlas.builtInstanceCount = primitiveCount;
|
tlas.builtInstanceCount = primitiveCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingElement3D::BuildTLAS(WebGPUCommandEncoderRef cmd, std::uint32_t index) {
|
void RenderingElement3D::BuildTLAS(WebGPUCommandEncoderRef cmd, std::uint32_t index, RTBuildPreference) {
|
||||||
|
// `preference` is ignored — the software LBVH TLAS build has no
|
||||||
|
// FAST_TRACE/FAST_BUILD equivalent. See the interface comment.
|
||||||
BuildTLASUpload(cmd, index);
|
BuildTLASUpload(cmd, index);
|
||||||
BuildTLASBuild(cmd, index);
|
BuildTLASBuild(cmd, index);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,18 +47,33 @@ void RenderingElement3D::Remove(RenderingElement3D* e) {
|
||||||
e->indexInElements = std::numeric_limits<std::uint32_t>::max();
|
e->indexInElements = std::numeric_limits<std::uint32_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index) {
|
void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTBuildPreference preference) {
|
||||||
auto& tlas = tlases[index];
|
auto& tlas = tlases[index];
|
||||||
const std::uint32_t primitiveCount = static_cast<std::uint32_t>(elements.size());
|
const std::uint32_t primitiveCount = static_cast<std::uint32_t>(elements.size());
|
||||||
|
|
||||||
|
// ALLOW_UPDATE is always set — BuildTLAS refits in place on later
|
||||||
|
// frames. The FAST_TRACE/FAST_BUILD preference is layered on top; the
|
||||||
|
// two preference bits are mutually exclusive, so exactly one is chosen.
|
||||||
|
// Both bits are baked into the AS at BUILD time and must be identical on
|
||||||
|
// every subsequent UPDATE, so a change in `preference` is treated as a
|
||||||
|
// topology change below to force a fresh rebuild with the new flags.
|
||||||
|
const VkBuildAccelerationStructureFlagsKHR buildFlags =
|
||||||
|
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR
|
||||||
|
| (preference == RTBuildPreference::FastBuild
|
||||||
|
? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
|
||||||
|
: VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
|
|
||||||
// Refit (UPDATE) is allowed when the count matches the count this AS
|
// Refit (UPDATE) is allowed when the count matches the count this AS
|
||||||
// was last built for. A change forces a full rebuild because the AS
|
// was last built for and the build flags are unchanged. A change forces
|
||||||
// storage and instance buffer were sized for the old count. Refit is
|
// a full rebuild because the AS storage and instance buffer were sized
|
||||||
// dramatically cheaper at scale (millions of instances) — it walks the
|
// for the old count (and a refit must inherit the original build flags).
|
||||||
// existing BVH and updates AABBs rather than reconstructing topology.
|
// Refit is dramatically cheaper at scale (millions of instances) — it
|
||||||
|
// walks the existing BVH and updates AABBs rather than reconstructing
|
||||||
|
// topology.
|
||||||
const bool topologyChanged =
|
const bool topologyChanged =
|
||||||
tlas.accelerationStructure == VK_NULL_HANDLE
|
tlas.accelerationStructure == VK_NULL_HANDLE
|
||||||
|| primitiveCount != tlas.builtInstanceCount;
|
|| primitiveCount != tlas.builtInstanceCount
|
||||||
|
|| buildFlags != tlas.builtFlags;
|
||||||
|
|
||||||
{
|
{
|
||||||
VkMemoryBarrier asBarrier {
|
VkMemoryBarrier asBarrier {
|
||||||
|
|
@ -118,10 +133,9 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index) {
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR tlasBuildGeometryInfo {
|
VkAccelerationStructureBuildGeometryInfoKHR tlasBuildGeometryInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
||||||
.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR,
|
.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR,
|
||||||
// ALLOW_UPDATE is required for any subsequent UPDATE-mode (refit)
|
// ALLOW_UPDATE (required for any subsequent UPDATE-mode refit) plus
|
||||||
// build. Set it on every build so the AS we keep around can be
|
// the caller's FAST_TRACE/FAST_BUILD preference — see buildFlags above.
|
||||||
// refit on later frames.
|
.flags = buildFlags,
|
||||||
.flags = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR,
|
|
||||||
.mode = topologyChanged
|
.mode = topologyChanged
|
||||||
? VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR
|
? VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR
|
||||||
: VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR,
|
: VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR,
|
||||||
|
|
@ -170,6 +184,7 @@ void RenderingElement3D::BuildTLAS(VkCommandBuffer cmd, std::uint32_t index) {
|
||||||
tlas.address = Device::vkGetAccelerationStructureDeviceAddressKHR(Device::device, &addrInfo);
|
tlas.address = Device::vkGetAccelerationStructureDeviceAddressKHR(Device::device, &addrInfo);
|
||||||
|
|
||||||
tlas.builtInstanceCount = primitiveCount;
|
tlas.builtInstanceCount = primitiveCount;
|
||||||
|
tlas.builtFlags = buildFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For UPDATE mode, src == dst (in-place refit). For BUILD, src is
|
// For UPDATE mode, src == dst (in-place refit). For BUILD, src is
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,12 @@ export namespace Crafter {
|
||||||
// reconstructs the topology from scratch. A change in count forces
|
// reconstructs the topology from scratch. A change in count forces
|
||||||
// a fresh rebuild because the AS is sized for that primitive count.
|
// a fresh rebuild because the AS is sized for that primitive count.
|
||||||
std::uint32_t builtInstanceCount = 0;
|
std::uint32_t builtInstanceCount = 0;
|
||||||
|
// Build flags the current AS was created with — ALLOW_UPDATE (always
|
||||||
|
// set, since BuildTLAS refits in place) plus the chosen
|
||||||
|
// FAST_TRACE/FAST_BUILD preference bit. A refit (UPDATE mode) must
|
||||||
|
// use flags identical to the originating build, so a change in the
|
||||||
|
// requested preference forces a full rebuild rather than a refit.
|
||||||
|
VkBuildAccelerationStructureFlagsKHR builtFlags = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderingElement3D {
|
class RenderingElement3D {
|
||||||
|
|
@ -78,7 +84,17 @@ export namespace Crafter {
|
||||||
|
|
||||||
static std::vector<RenderingElement3D*> elements;
|
static std::vector<RenderingElement3D*> elements;
|
||||||
inline static TlasWithBuffer tlases[Window::numFrames];
|
inline static TlasWithBuffer tlases[Window::numFrames];
|
||||||
static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index);
|
// Build (or in-place refit) the TLAS for frame `index`. `preference`
|
||||||
|
// maps onto the FAST_TRACE/FAST_BUILD bits exactly as Mesh::Build
|
||||||
|
// does for a BLAS: FastTrace (the default) spends more build time for
|
||||||
|
// faster traversal — right for a TLAS rebuilt at most once per frame
|
||||||
|
// and traced many times; FastBuild trades traversal speed for cheaper
|
||||||
|
// builds, for scenes whose instance set churns hard every frame.
|
||||||
|
// ALLOW_UPDATE is always set (refit is intrinsic to this path), so it
|
||||||
|
// is not exposed as an option. Changing `preference` between frames
|
||||||
|
// forces a full rebuild on the next call, since a refit must inherit
|
||||||
|
// the original build's flags.
|
||||||
|
static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index, RTBuildPreference preference = RTBuildPreference::FastTrace);
|
||||||
|
|
||||||
// Register / unregister with `elements`. Use these instead of touching
|
// Register / unregister with `elements`. Use these instead of touching
|
||||||
// the vector directly: linear find+erase is O(n) and pathological at
|
// the vector directly: linear find+erase is O(n) and pathological at
|
||||||
|
|
@ -183,7 +199,11 @@ export namespace Crafter {
|
||||||
// interleave a compute pass (e.g. the ctor-time first build).
|
// interleave a compute pass (e.g. the ctor-time first build).
|
||||||
static void BuildTLASUpload(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
static void BuildTLASUpload(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
||||||
static void BuildTLASBuild(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
static void BuildTLASBuild(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
||||||
static void BuildTLAS(WebGPUCommandEncoderRef cmd, std::uint32_t index);
|
// `preference` mirrors the Vulkan signature for portability but has
|
||||||
|
// no effect here: the software LBVH-for-TLAS path has no hardware
|
||||||
|
// FAST_TRACE/FAST_BUILD knob (same as Mesh::Build on WebGPU). The
|
||||||
|
// parameter exists purely so portable code compiles unchanged.
|
||||||
|
static void BuildTLAS(WebGPUCommandEncoderRef cmd, std::uint32_t index, RTBuildPreference preference = RTBuildPreference::FastTrace);
|
||||||
|
|
||||||
static void Add(RenderingElement3D* e);
|
static void Add(RenderingElement3D* e);
|
||||||
static void Remove(RenderingElement3D* e);
|
static void Remove(RenderingElement3D* e);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue