need help as to why raii “device.createAccelerationStructureKHR(create_info)” is not working for me.
i got a AS helper class like the following, which is directly translated from non-raii version.
class vk_AccStruct_raii
{
public:
vk_AccStruct_raii() = default;
void build_bl(const vk::raii::Device& device, const vk::raii::PhysicalDevice& pDevice,
const vk::raii::CommandPool& cmdPool, const vk::raii::Queue& queue,
const vk::PhysicalDeviceAccelerationStructurePropertiesKHR* asProp,
const std::vector<vk::AccelerationStructureGeometryKHR>& as_geo,
const std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>>& as_bdRanges,
bool allowUpdate);
void build_tl(const vk::raii::Device& device, const vk::raii::PhysicalDevice& pDevice,
const vk::raii::CommandPool& cmdPool, const vk::raii::Queue& queue,
const vk::PhysicalDeviceAccelerationStructurePropertiesKHR* asProp,
const std::vector<vk::AccelerationStructureGeometryKHR>& as_geo,
const std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>>& as_bdRanges,
bool allowUpdate);
... ...
private:
struct as_BuildSizes
{
as_BuildSizes() :
accelerationStructureSize_offset(0), updateScratchSize_offset(0), buildScratchSize_offset(0),
accelerationStructureSize(0), updateScratchSize(0), buildScratchSize(0) { }
as_BuildSizes(
vk::DeviceSize asSizeOffset, vk::DeviceSize updScrtachSizeOffset, vk::DeviceSize bScratchSizeOffset,
vk::DeviceSize asSize, vk::DeviceSize updScratchSize, vk::DeviceSize bSratchSize) :
accelerationStructureSize_offset(asSizeOffset), updateScratchSize_offset(updScrtachSizeOffset), buildScratchSize_offset(bScratchSizeOffset),
accelerationStructureSize(asSize), updateScratchSize(updScratchSize), buildScratchSize(bSratchSize) { }
vk::DeviceSize accelerationStructureSize_offset;
vk::DeviceSize updateScratchSize_offset;
vk::DeviceSize buildScratchSize_offset;
vk::DeviceSize accelerationStructureSize;
vk::DeviceSize updateScratchSize;
vk::DeviceSize buildScratchSize;
};
std::vector<vk::AccelerationStructureKHR> _as_Handles;
vk::raii::Buffer _as_buff { nullptr };
vk::raii::DeviceMemory _as_buff_DevMem { nullptr };
/*
* 0 = not built,
* 1 = bottom level
* 2 = top level
*/
uint32_t _buildState {0};
};
build_xx method implement :
void vk_AccStruct_raii::build_bl(const vk::raii::Device& device, const vk::raii::PhysicalDevice& pDevice,
const vk::raii::CommandPool& cmdPool, const vk::raii::Queue& queue,
const vk::PhysicalDeviceAccelerationStructurePropertiesKHR* asProp,
const std::vector<vk::AccelerationStructureGeometryKHR>& as_geo,
const std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>>& as_bdRanges, bool allowUpdate)
{
if (_buildState > 0)return;
TBVK_ASSERT(as_geo.size() == as_bdRanges.size(), "TriangleData & BuildRange Data Size Not Equal");
#if TBVK_DEBUG_ON
for (const auto& data : as_geo)
TBVK_ASSERT(data.geometryType == vk::GeometryTypeKHR::eTriangles, "[triPrimitiveData] Contained Non-Triangle Data");
#endif // TBVK_DEBUG_ON
// Helper function to align a value to a given alignment
const auto alignUp = [](auto value, size_t alignment) noexcept { return ((value + alignment - 1) & ~(alignment - 1)); };
const auto geoSize = static_cast<uint32_t>(as_geo.size());
// accumulate total sizes
vk::DeviceSize accelerationStructureSize = 0;
vk::DeviceSize updateScratchSize = 0;
vk::DeviceSize buildScratchSize = 0;
std::vector<vk::AccelerationStructureBuildGeometryInfoKHR> bd_geo_infos;
bd_geo_infos.reserve(geoSize);
std::vector<const vk::AccelerationStructureBuildRangeInfoKHR*> bd_ranges_list;
bd_ranges_list.reserve(geoSize);
std::vector<as_BuildSizes> geo_bd_sizes;
geo_bd_sizes.reserve(geoSize);
for (uint32_t i = 0; i < geoSize; ++i)
{
const auto& bRangeList = as_bdRanges[i];
const auto bRangeCount = bRangeList.size(); // build range count : its SubMesh Count for triangle data (only meaningful context)
uint32_t maxPrimCount = 0;
for (uint32_t br = 0; br < bRangeCount; ++br)maxPrimCount += bRangeList[br].primitiveCount;
bd_ranges_list.push_back(bRangeList.data());
// only different in Build Info Struct
auto buildInfo = TbUtils_Vk_Raii::as_BuildGeoInfo_BL(allowUpdate);
buildInfo.geometryCount = bRangeCount; // is here telling how many BuildRange that this "VkAccelerationStructureGeometryKHR" has ???
buildInfo.pGeometries = &as_geo[i];
buildInfo.dstAccelerationStructure = VK_NULL_HANDLE; // will fill in later
buildInfo.scratchData = {}; // will fill in later
bd_geo_infos.push_back(buildInfo);
vk::AccelerationStructureBuildSizesInfoKHR q_build_size =
device.getAccelerationStructureBuildSizesKHR(
vk::AccelerationStructureBuildTypeKHR::eDevice, // or vk::AccelerationStructureBuildTypeKHR::eHost if build_on_host is preferred
buildInfo, { maxPrimCount });
// diff from scratch. AS requires multiple of 256 size
auto c_accelerationStructureSize = alignUp(q_build_size.accelerationStructureSize, 256u);
auto c_updateScratchSize = alignUp(q_build_size.updateScratchSize, asProp->minAccelerationStructureScratchOffsetAlignment);
auto c_buildScratchSize = alignUp(q_build_size.buildScratchSize, asProp->minAccelerationStructureScratchOffsetAlignment);
geo_bd_sizes.emplace_back(
accelerationStructureSize, updateScratchSize, buildScratchSize, // offsets
c_accelerationStructureSize, c_updateScratchSize, c_buildScratchSize // sizes
);
#if TBVK_DEBUG_ON
printf("BL::>accelerationStructure_Offset:[%llu] | updateScratch_Offset:[%llu] | buildScratch_Offset:[%llu]\n",
accelerationStructureSize, updateScratchSize, buildScratchSize);
printf("BL::>GeoIndex:[%u]Align:[%u] | accelerationStructure:[%llu]Align:[%llu] | updateScratch:[%llu]Align:[%llu] | buildScratch:[%llu]Align:[%llu]\n",
i, asProp->minAccelerationStructureScratchOffsetAlignment,
q_build_size.accelerationStructureSize, c_accelerationStructureSize,
q_build_size.updateScratchSize, c_updateScratchSize,
q_build_size.buildScratchSize, c_buildScratchSize
);
#endif // TBVK_DEBUG_ON
accelerationStructureSize += c_accelerationStructureSize;
updateScratchSize += c_updateScratchSize;
buildScratchSize += c_buildScratchSize;
#if TBVK_DEBUG_ON
printf("BL::>Accumulated --> accelerationStructureSize:[%llu] | updateScratchSize:[%llu] | buildScratchSize:[%llu]\n",
accelerationStructureSize, updateScratchSize, buildScratchSize);
#endif // TBVK_DEBUG_ON
}
// create the actual buffer for the AS
// create the actual AS buffer (BL)
const vk::SharingMode sharingMode = vk::SharingMode::eExclusive;
const vk::MemoryPropertyFlags memPropFlag = vk::MemoryPropertyFlagBits::eDeviceLocal;
vk::MemoryAllocateFlagsInfoKHR flags_info{ };
flags_info.flags = vk::MemoryAllocateFlagBits::eDeviceAddress;
const vk::BufferUsageFlags usage =
vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR |
vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eShaderDeviceAddress;
TbUtils_Vk_Raii::vkCreate_Buffer(device, pDevice,
_as_buff, _as_buff_DevMem,
accelerationStructureSize,
usage, memPropFlag, sharingMode,
nullptr, &flags_info);
// create the scratch buffer (will be deleted at the end, not worrying about update here la
const vk::DeviceSize scratch_size = allowUpdate ? buildScratchSize : updateScratchSize;
vk::raii::Buffer _tmpAsBuff_Scratch{ nullptr };
vk::raii::DeviceMemory _tmpAsBuff_Scratch_DevMem{ nullptr };
TbUtils_Vk_Raii::vkCreate_Buffer(device, pDevice,
_tmpAsBuff_Scratch, _tmpAsBuff_Scratch_DevMem,
scratch_size,
usage, memPropFlag, sharingMode,
nullptr, &flags_info);
// get the device address of the scratch buffer
const vk::DeviceAddress scratchBuffAddress = TbUtils_Vk_Raii::vkQuery_DeviceAddress(device, _tmpAsBuff_Scratch);
#if USE_OLD_API_CREATE_AS
_as_Handles.reserve(geoSize);
for (uint32_t i = 0; i < geoSize; ++i)
{
auto* as_build_geo_info = &bd_geo_infos[i];
auto* as_build_size_info = &geo_bd_sizes[i];
// have to mix in using the old api, device
// device.createAccelerationStructureKHR(create_info) would not work
VkAccelerationStructureCreateInfoKHR create_info{};
create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
create_info.type = static_cast<VkAccelerationStructureTypeKHR>(as_build_geo_info->type);
create_info.buffer = *_as_buff;
create_info.offset = as_build_size_info->accelerationStructureSize_offset; // ensure buffer device address is aligned
create_info.size = as_build_size_info->accelerationStructureSize; // build_sizes.accelerationStructureSize;
VkAccelerationStructureKHR ea_as;
TBVK_ASSERT(vkCreateAccelerationStructureKHR != nullptr, "ERROR :: Func Ptr NULL : vkCreateAccelerationStructureKHR");
vkCreateAccelerationStructureKHR(*device, &create_info, nullptr, &ea_as);
_as_Handles.emplace_back(vk::AccelerationStructureKHR(ea_as));
const VkDeviceSize scratch_offset = allowUpdate ?
as_build_size_info->buildScratchSize_offset :
as_build_size_info->updateScratchSize_offset;
as_build_geo_info->scratchData.deviceAddress = scratchBuffAddress + scratch_offset;
as_build_geo_info->dstAccelerationStructure = _as_Handles[i];
}
#else
/////////////////////////////////////////////////////////////////////////////////////////////////////
// for some unknown reason, device.createAccelerationStructureKHR would produce invalid AS
_as_Handles.reserve(geoSize);
for (uint32_t i = 0; i < geoSize; ++i)
{
auto* as_build_geo_info = &bd_geo_infos[i];
auto* as_build_size_info = &geo_bd_sizes[i];
vk::AccelerationStructureCreateInfoKHR create_info{};
create_info.type = as_build_geo_info->type;
create_info.buffer = *_as_buff;
create_info.offset = as_build_size_info->accelerationStructureSize_offset; // ensure buffer device address is aligned
create_info.size = as_build_size_info->accelerationStructureSize; // build_sizes.accelerationStructureSize;
// create the as_handle in place
_as_Handles.emplace_back(device.createAccelerationStructureKHR(create_info));
const VkDeviceSize scratch_offset = allowUpdate ?
as_build_size_info->buildScratchSize_offset :
as_build_size_info->updateScratchSize_offset;
as_build_geo_info->scratchData.deviceAddress = scratchBuffAddress + scratch_offset;
as_build_geo_info->dstAccelerationStructure = _as_Handles[i];
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
auto tmpCmd = TbUtils_Vk_Raii::vkCmd_Single_Begin(device, cmdPool);
tmpCmd.buildAccelerationStructuresKHR(bd_geo_infos, bd_ranges_list);
TbUtils_Vk_Raii::vkCmd_Single_End(queue, tmpCmd);
//// raii api no need to explicit clean up
//// clean up the scratch buffer ??? both build and update ???
//TbUtils_Vk::vkDestroy_Buffer(device, _tmpAsBuff_Scratch, _tmpAsBuff_Scratch_DevMem);
_buildState = 1;
printf("....BLAS Built Completed....\n");
}
the problem was that i have to mix in the (non-raii) deviceCreateAS api, so that the validation wont complaint
when i build_tl / build_bl without “USE_OLD_API_CREATE_AS” defined (using raii deviceCreateAS api), validation error stating invalid AS, it would crash before build_xx can finish:
so i have to mixed in non-raii deviceCreateAS api
(with “USE_OLD_API_CREATE_AS” defined) , build_xx can complete without any validation err/warning

