feat(vulkan-rt): Mesh::BuildProcedural — AABB (procedural) BLAS build path (#33) #35
2 changed files with 88 additions and 26 deletions
feat(vulkan-rt): Mesh::BuildProcedural — AABB (procedural) BLAS build path (#33)
Adds the native counterpart of the WebGPU Mesh::BuildProcedural: uploads the boxes as a 24-byte-stride VkAabbPositionsKHR-compatible device buffer (AS-build-input read-only + device address) and builds the BLAS from one VK_GEOMETRY_TYPE_AABBS_KHR geometry. opaque maps to VK_GEOMETRY_OPAQUE_BIT_KHR, default-false semantics matching the WebGPU path so any-hit shaders run. The BLAS sizing/create/build tail is factored into a geometry-type-agnostic helper shared with the triangle path; no TLAS/instance changes needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
commit
a9e42f9c90
|
|
@ -39,31 +39,10 @@ namespace {
|
|||
constexpr VkBufferUsageFlags2 kIndexUsageBase =
|
||||
kVertexUsageBase | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
|
||||
void RecordBLASBuild(Mesh& self, std::uint32_t vertexCount, std::uint32_t indexCount, VkCommandBuffer cmd) {
|
||||
VkDeviceOrHostAddressConstKHR vertexAddr;
|
||||
vertexAddr.deviceAddress = self.vertexBuffer.address;
|
||||
|
||||
VkDeviceOrHostAddressConstKHR indexAddr;
|
||||
indexAddr.deviceAddress = self.indexBuffer.address;
|
||||
|
||||
auto trianglesData = VkAccelerationStructureGeometryTrianglesDataKHR {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
||||
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.vertexData = vertexAddr,
|
||||
.vertexStride = sizeof(Vector<float, 3, 3>),
|
||||
.maxVertex = vertexCount - 1,
|
||||
.indexType = VK_INDEX_TYPE_UINT32,
|
||||
.indexData = indexAddr,
|
||||
.transformData = {.deviceAddress = 0}
|
||||
};
|
||||
VkAccelerationStructureGeometryDataKHR geometryData(trianglesData);
|
||||
VkAccelerationStructureGeometryKHR blasGeometry {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
||||
.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR,
|
||||
.geometry = geometryData,
|
||||
.flags = VK_GEOMETRY_OPAQUE_BIT_KHR
|
||||
};
|
||||
|
||||
// Shared BLAS sizing / creation / build-record tail — geometry-type
|
||||
// agnostic; both the triangle and the AABB (procedural) paths feed
|
||||
// their single geometry through here.
|
||||
void RecordBLASBuildFromGeometry(Mesh& self, const VkAccelerationStructureGeometryKHR& blasGeometry, std::uint32_t primitiveCount, VkCommandBuffer cmd) {
|
||||
VkAccelerationStructureBuildGeometryInfoKHR blasBuildGeometryInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
||||
.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR,
|
||||
|
|
@ -72,7 +51,6 @@ namespace {
|
|||
.pGeometries = &blasGeometry,
|
||||
};
|
||||
|
||||
auto primitiveCount = indexCount / 3;
|
||||
VkAccelerationStructureBuildSizesInfoKHR blasBuildSizes = {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR
|
||||
};
|
||||
|
|
@ -122,6 +100,34 @@ namespace {
|
|||
};
|
||||
self.blasAddr = Device::vkGetAccelerationStructureDeviceAddressKHR(Device::device, &addrInfo);
|
||||
}
|
||||
|
||||
void RecordBLASBuild(Mesh& self, std::uint32_t vertexCount, std::uint32_t indexCount, VkCommandBuffer cmd) {
|
||||
VkDeviceOrHostAddressConstKHR vertexAddr;
|
||||
vertexAddr.deviceAddress = self.vertexBuffer.address;
|
||||
|
||||
VkDeviceOrHostAddressConstKHR indexAddr;
|
||||
indexAddr.deviceAddress = self.indexBuffer.address;
|
||||
|
||||
auto trianglesData = VkAccelerationStructureGeometryTrianglesDataKHR {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
||||
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.vertexData = vertexAddr,
|
||||
.vertexStride = sizeof(Vector<float, 3, 3>),
|
||||
.maxVertex = vertexCount - 1,
|
||||
.indexType = VK_INDEX_TYPE_UINT32,
|
||||
.indexData = indexAddr,
|
||||
.transformData = {.deviceAddress = 0}
|
||||
};
|
||||
VkAccelerationStructureGeometryDataKHR geometryData(trianglesData);
|
||||
VkAccelerationStructureGeometryKHR blasGeometry {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
||||
.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR,
|
||||
.geometry = geometryData,
|
||||
.flags = VK_GEOMETRY_OPAQUE_BIT_KHR
|
||||
};
|
||||
|
||||
RecordBLASBuildFromGeometry(self, blasGeometry, indexCount / 3, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::Build(std::span<Vector<float, 3, 3>> verticies, std::span<std::uint32_t> indicies, VkCommandBuffer cmd) {
|
||||
|
|
@ -203,3 +209,32 @@ void Mesh::Build(const CompressedMeshAsset& asset, VkCommandBuffer cmd) {
|
|||
RecordBLASBuild(*this, asset.vertexCount, asset.indexCount, cmd);
|
||||
}
|
||||
|
||||
void Mesh::BuildProcedural(std::span<const RTAabb> aabbs, bool opaque, VkCommandBuffer cmd) {
|
||||
this->opaque = opaque;
|
||||
|
||||
// 24-byte-stride VkAabbPositionsKHR-compatible build input
|
||||
// (static_assert'd in the interface). Same usage set as the triangle
|
||||
// inputs: AS-build read-only + device address.
|
||||
aabbBuffer.Resize(kVertexUsageBase, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, static_cast<std::uint32_t>(aabbs.size()));
|
||||
std::memcpy(aabbBuffer.value, aabbs.data(), aabbs.size() * sizeof(RTAabb));
|
||||
aabbBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
||||
|
||||
VkAccelerationStructureGeometryAabbsDataKHR aabbsData {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR,
|
||||
.data = { .deviceAddress = aabbBuffer.address },
|
||||
.stride = sizeof(RTAabb)
|
||||
};
|
||||
VkAccelerationStructureGeometryDataKHR geometryData;
|
||||
geometryData.aabbs = aabbsData;
|
||||
VkAccelerationStructureGeometryKHR blasGeometry {
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
||||
.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR,
|
||||
.geometry = geometryData,
|
||||
// Non-opaque by default (mirrors the WebGPU path) so any-hit
|
||||
// shaders run for procedural geometry unless the caller opts out.
|
||||
.flags = opaque ? static_cast<VkGeometryFlagsKHR>(VK_GEOMETRY_OPAQUE_BIT_KHR) : VkGeometryFlagsKHR{}
|
||||
};
|
||||
|
||||
RecordBLASBuildFromGeometry(*this, blasGeometry, static_cast<std::uint32_t>(aabbs.size()), cmd);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,12 +31,27 @@ import Crafter.Asset;
|
|||
import :VulkanBuffer;
|
||||
|
||||
export namespace Crafter {
|
||||
// One procedural primitive's axis-aligned bounding box, in object
|
||||
// space. Layout-compatible with VkAabbPositionsKHR (24-byte stride),
|
||||
// so a span of these uploads directly as a
|
||||
// VK_GEOMETRY_TYPE_AABBS_KHR build input. Mirrors the DOM-side
|
||||
// definition below so portable user code compiles unchanged.
|
||||
struct RTAabb {
|
||||
float min[3];
|
||||
float max[3];
|
||||
};
|
||||
static_assert(sizeof(RTAabb) == sizeof(VkAabbPositionsKHR));
|
||||
|
||||
class Mesh {
|
||||
public:
|
||||
VulkanBuffer<char, false> scratchBuffer;
|
||||
VulkanBuffer<char, false> blasBuffer;
|
||||
VulkanBuffer<Vector<float, 3, 3>, true> vertexBuffer;
|
||||
VulkanBuffer<std::uint32_t, true> indexBuffer;
|
||||
// AABB build input for the procedural path (BuildProcedural).
|
||||
// Lifetime contract matches vertexBuffer/indexBuffer: must stay
|
||||
// alive until the build submitted on `cmd` completes.
|
||||
VulkanBuffer<RTAabb, true> aabbBuffer;
|
||||
// Lives until the cmd buffer issued by the compressed Build path
|
||||
// completes execution. Kept as a member so the recorded
|
||||
// vkCmdDecompressMemoryEXT references valid memory until the queue
|
||||
|
|
@ -57,6 +72,18 @@ export namespace Crafter {
|
|||
// Region 2 (data) is not consumed here — the caller decompresses it
|
||||
// into their own buffer if needed (or uses Compression::DecompressCPU).
|
||||
void Build(const ::Crafter::CompressedMeshAsset& asset, VkCommandBuffer cmd);
|
||||
// Build an AABB (procedural) BLAS from a list of object-space
|
||||
// boxes (VK_GEOMETRY_TYPE_AABBS_KHR). The hit group bound to
|
||||
// instances of this mesh must be a
|
||||
// VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR group
|
||||
// carrying an intersection shader; that shader is invoked for
|
||||
// each box the ray enters and reports the surface hit via
|
||||
// reportIntersectionEXT. `opaque` maps to
|
||||
// VK_GEOMETRY_OPAQUE_BIT_KHR: pass false (the WebGPU-path
|
||||
// default) to let any-hit shaders run. Same scratch/lifetime
|
||||
// handling as the triangle Build; instances reference blasAddr
|
||||
// exactly like a triangle BLAS.
|
||||
void BuildProcedural(std::span<const RTAabb> aabbs, bool opaque, VkCommandBuffer cmd);
|
||||
};
|
||||
}
|
||||
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue