You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
10 KiB
230 lines
10 KiB
/*
|
|
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
/**
|
|
|
|
\class nvvk::RaytracingBuilderKHR
|
|
|
|
\brief nvvk::RaytracingBuilderKHR is a base functionality of raytracing
|
|
|
|
This class acts as an owning container for a single top-level acceleration
|
|
structure referencing any number of bottom-level acceleration structures.
|
|
We provide functions for building (on the device) an array of BLASs and a
|
|
single TLAS from vectors of BlasInput and Instance, respectively, and
|
|
a destroy function for cleaning up the created acceleration structures.
|
|
|
|
Generally, we reference BLASs by their index in the stored BLAS array,
|
|
rather than using raw device pointers as the pure Vulkan acceleration
|
|
structure API uses.
|
|
|
|
This class does not support replacing acceleration structures once
|
|
built, but you can update the acceleration structures. For educational
|
|
purposes, this class prioritizes (relative) understandability over
|
|
performance, so vkQueueWaitIdle is implicitly used everywhere.
|
|
|
|
# Setup and Usage
|
|
\code{.cpp}
|
|
// Borrow a VkDevice and memory allocator pointer (must remain
|
|
// valid throughout our use of the ray trace builder), and
|
|
// instantiate an unspecified queue of the given family for use.
|
|
m_rtBuilder.setup(device, memoryAllocator, queueIndex);
|
|
|
|
// You create a vector of RayTracingBuilderKHR::BlasInput then
|
|
// pass it to buildBlas.
|
|
std::vector<RayTracingBuilderKHR::BlasInput> inputs = // ...
|
|
m_rtBuilder.buildBlas(inputs);
|
|
|
|
// You create a vector of RaytracingBuilder::Instance and pass to
|
|
// buildTlas. The blasId member of each instance must be below
|
|
// inputs.size() (above).
|
|
std::vector<VkAccelerationStructureInstanceKHR> instances = // ...
|
|
m_rtBuilder.buildTlas(instances);
|
|
|
|
// Retrieve the handle to the acceleration structure.
|
|
const VkAccelerationStructureKHR tlas = m.rtBuilder.getAccelerationStructure()
|
|
\endcode
|
|
*/
|
|
|
|
#include <mutex>
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
#if VK_KHR_acceleration_structure
|
|
|
|
#include "resourceallocator_vk.hpp"
|
|
#include "commands_vk.hpp" // this is only needed here to satisfy some samples that rely on it
|
|
#include "debug_util_vk.hpp"
|
|
#include "nvh/nvprint.hpp" // this is only needed here to satisfy some samples that rely on it
|
|
#include "nvmath/nvmath.h"
|
|
#include <type_traits>
|
|
|
|
|
|
namespace nvvk {
|
|
|
|
// Convert a Mat4x4 to the matrix required by acceleration structures
|
|
inline VkTransformMatrixKHR toTransformMatrixKHR(nvmath::mat4f matrix)
|
|
{
|
|
// VkTransformMatrixKHR uses a row-major memory layout, while nvmath::mat4f
|
|
// uses a column-major memory layout. We transpose the matrix so we can
|
|
// memcpy the matrix's data directly.
|
|
nvmath::mat4f temp = nvmath::transpose(matrix);
|
|
VkTransformMatrixKHR out_matrix;
|
|
memcpy(&out_matrix, &temp, sizeof(VkTransformMatrixKHR));
|
|
return out_matrix;
|
|
}
|
|
|
|
// Ray tracing BLAS and TLAS builder
|
|
class RaytracingBuilderKHR
|
|
{
|
|
public:
|
|
// Inputs used to build Bottom-level acceleration structure.
|
|
// You manage the lifetime of the buffer(s) referenced by the VkAccelerationStructureGeometryKHRs within.
|
|
// In particular, you must make sure they are still valid and not being modified when the BLAS is built or updated.
|
|
struct BlasInput
|
|
{
|
|
// Data used to build acceleration structure geometry
|
|
std::vector<VkAccelerationStructureGeometryKHR> asGeometry;
|
|
std::vector<VkAccelerationStructureBuildRangeInfoKHR> asBuildOffsetInfo;
|
|
VkBuildAccelerationStructureFlagsKHR flags{0};
|
|
};
|
|
|
|
// Initializing the allocator and querying the raytracing properties
|
|
void setup(const VkDevice& device, nvvk::ResourceAllocator* allocator, uint32_t queueIndex);
|
|
|
|
// Destroying all allocations
|
|
void destroy();
|
|
|
|
// Returning the constructed top-level acceleration structure
|
|
VkAccelerationStructureKHR getAccelerationStructure() const;
|
|
|
|
// Return the Acceleration Structure Device Address of a BLAS Id
|
|
VkDeviceAddress getBlasDeviceAddress(uint32_t blasId);
|
|
|
|
// Create all the BLAS from the vector of BlasInput
|
|
void buildBlas(const std::vector<BlasInput>& input,
|
|
VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
|
|
|
// Refit BLAS number blasIdx from updated buffer contents.
|
|
void updateBlas(uint32_t blasIdx, BlasInput& blas, VkBuildAccelerationStructureFlagsKHR flags);
|
|
|
|
// Build TLAS for static acceleration structures
|
|
void buildTlas(const std::vector<VkAccelerationStructureInstanceKHR>& instances,
|
|
VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR,
|
|
bool update = false);
|
|
|
|
#ifdef VK_NV_ray_tracing_motion_blur
|
|
// Build TLAS for mix of motion and static acceleration structures
|
|
void buildTlas(const std::vector<VkAccelerationStructureMotionInstanceNV>& instances,
|
|
VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV,
|
|
bool update = false);
|
|
#endif
|
|
|
|
// Build TLAS from an array of VkAccelerationStructureInstanceKHR
|
|
// - Use motion=true with VkAccelerationStructureMotionInstanceNV
|
|
// - The resulting TLAS will be stored in m_tlas
|
|
// - update is to rebuild the Tlas with updated matrices, flag must have the 'allow_update'
|
|
template <class T>
|
|
void buildTlas(const std::vector<T>& instances,
|
|
VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR,
|
|
bool update = false,
|
|
bool motion = false)
|
|
{
|
|
// Cannot call buildTlas twice except to update.
|
|
assert(m_tlas.accel == VK_NULL_HANDLE || update);
|
|
uint32_t countInstance = static_cast<uint32_t>(instances.size());
|
|
|
|
// Command buffer to create the TLAS
|
|
nvvk::CommandPool genCmdBuf(m_device, m_queueIndex);
|
|
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
|
|
|
// Create a buffer holding the actual instance data (matrices++) for use by the AS builder
|
|
nvvk::Buffer instancesBuffer; // Buffer of instances containing the matrices and BLAS ids
|
|
instancesBuffer = m_alloc->createBuffer(cmdBuf, instances,
|
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
|
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR);
|
|
NAME_VK(instancesBuffer.buffer);
|
|
VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, instancesBuffer.buffer};
|
|
VkDeviceAddress instBufferAddr = vkGetBufferDeviceAddress(m_device, &bufferInfo);
|
|
|
|
// Make sure the copy of the instance buffer are copied before triggering the acceleration structure build
|
|
VkMemoryBarrier barrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
|
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
0, 1, &barrier, 0, nullptr, 0, nullptr);
|
|
|
|
// Creating the TLAS
|
|
nvvk::Buffer scratchBuffer;
|
|
cmdCreateTlas(cmdBuf, countInstance, instBufferAddr, scratchBuffer, flags, update, motion);
|
|
|
|
// Finalizing and destroying temporary data
|
|
genCmdBuf.submitAndWait(cmdBuf); // queueWaitIdle inside.
|
|
m_alloc->finalizeAndReleaseStaging();
|
|
m_alloc->destroy(scratchBuffer);
|
|
m_alloc->destroy(instancesBuffer);
|
|
}
|
|
|
|
// Creating the TLAS, called by buildTlas
|
|
void cmdCreateTlas(VkCommandBuffer cmdBuf, // Command buffer
|
|
uint32_t countInstance, // number of instances
|
|
VkDeviceAddress instBufferAddr, // Buffer address of instances
|
|
nvvk::Buffer& scratchBuffer, // Scratch buffer for construction
|
|
VkBuildAccelerationStructureFlagsKHR flags, // Build creation flag
|
|
bool update, // Update == animation
|
|
bool motion // Motion Blur
|
|
);
|
|
|
|
|
|
protected:
|
|
std::vector<nvvk::AccelKHR> m_blas; // Bottom-level acceleration structure
|
|
nvvk::AccelKHR m_tlas; // Top-level acceleration structure
|
|
|
|
// Setup
|
|
VkDevice m_device{VK_NULL_HANDLE};
|
|
uint32_t m_queueIndex{0};
|
|
nvvk::ResourceAllocator* m_alloc{nullptr};
|
|
nvvk::DebugUtil m_debug;
|
|
nvvk::CommandPool m_cmdPool;
|
|
|
|
struct BuildAccelerationStructure
|
|
{
|
|
VkAccelerationStructureBuildGeometryInfoKHR buildInfo{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR};
|
|
VkAccelerationStructureBuildSizesInfoKHR sizeInfo{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
|
|
const VkAccelerationStructureBuildRangeInfoKHR* rangeInfo;
|
|
nvvk::AccelKHR as; // result acceleration structure
|
|
nvvk::AccelKHR cleanupAS;
|
|
};
|
|
|
|
|
|
void cmdCreateBlas(VkCommandBuffer cmdBuf,
|
|
std::vector<uint32_t> indices,
|
|
std::vector<BuildAccelerationStructure>& buildAs,
|
|
VkDeviceAddress scratchAddress,
|
|
VkQueryPool queryPool);
|
|
void cmdCompactBlas(VkCommandBuffer cmdBuf, std::vector<uint32_t> indices, std::vector<BuildAccelerationStructure>& buildAs, VkQueryPool queryPool);
|
|
void destroyNonCompacted(std::vector<uint32_t> indices, std::vector<BuildAccelerationStructure>& buildAs);
|
|
bool hasFlag(VkFlags item, VkFlags flag) { return (item & flag) == flag; }
|
|
};
|
|
|
|
} // namespace nvvk
|
|
|
|
#else
|
|
#error This include requires VK_KHR_acceleration_structure support in the Vulkan SDK.
|
|
#endif
|
|
|