blob: 25eeed52f1fca2a84b34629bb8cf37293e058614 [file] [log] [blame]
/*
* Copyright (c) 2015-2024 The Khronos Group Inc.
* Copyright (c) 2015-2024 Valve Corporation
* Copyright (c) 2015-2024 LunarG, Inc.
* Copyright (c) 2015-2024 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. 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
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/ray_tracing_objects.h"
#include "../framework/descriptor_helper.h"
#include "../framework/shader_helper.h"
#include "../layers/utils/vk_layer_utils.h"
TEST_F(NegativeRayTracing, BarrierAccessAccelerationStructure) {
TEST_DESCRIPTION("Test barrier with access ACCELERATION_STRUCTURE bit.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
VkMemoryBarrier2 mem_barrier = vku::InitStructHelper();
mem_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
VkDependencyInfo dependency_info = vku::InitStructHelper();
dependency_info.memoryBarrierCount = 1;
dependency_info.pMemoryBarriers = &mem_barrier;
m_commandBuffer->begin();
mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-srcAccessMask-03927");
vk::CmdPipelineBarrier2KHR(m_commandBuffer->handle(), &dependency_info);
mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-srcAccessMask-03928");
vk::CmdPipelineBarrier2KHR(m_commandBuffer->handle(), &dependency_info);
mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-dstAccessMask-03927");
vk::CmdPipelineBarrier2KHR(m_commandBuffer->handle(), &dependency_info);
mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-dstAccessMask-03928");
vk::CmdPipelineBarrier2KHR(m_commandBuffer->handle(), &dependency_info);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BarrierSync2AccessAccelerationStructureRayQueryDisabled) {
TEST_DESCRIPTION(
"Test sync2 barrier with ACCELERATION_STRUCTURE_READ memory access."
"Ray query feature is not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
VkMemoryBarrier2 mem_barrier = vku::InitStructHelper();
mem_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
vkt::Buffer buffer(*m_device, 32);
VkBufferMemoryBarrier2 buffer_barrier = vku::InitStructHelper();
buffer_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
buffer_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
buffer_barrier.buffer = buffer.handle();
buffer_barrier.size = 32;
VkImageObj image(m_device);
image.Init(128, 128, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
ASSERT_TRUE(image.initialized());
VkImageMemoryBarrier2 image_barrier = vku::InitStructHelper();
image_barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
image_barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
image_barrier.image = image.handle();
image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
VkDependencyInfo dependency_info = vku::InitStructHelper();
dependency_info.memoryBarrierCount = 1;
dependency_info.pMemoryBarriers = &mem_barrier;
dependency_info.bufferMemoryBarrierCount = 1;
dependency_info.pBufferMemoryBarriers = &buffer_barrier;
dependency_info.imageMemoryBarrierCount = 1;
dependency_info.pImageMemoryBarriers = &image_barrier;
m_commandBuffer->begin();
mem_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
mem_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
buffer_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
image_barrier.srcAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
mem_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
mem_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
buffer_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
image_barrier.dstAccessMask = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-srcAccessMask-06256");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBufferMemoryBarrier2-srcAccessMask-06256");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageMemoryBarrier2-srcAccessMask-06256");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryBarrier2-dstAccessMask-06256");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBufferMemoryBarrier2-dstAccessMask-06256");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageMemoryBarrier2-dstAccessMask-06256");
vk::CmdPipelineBarrier2KHR(m_commandBuffer->handle(), &dependency_info);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BarrierSync1AccessAccelerationStructureRayQueryDisabled) {
TEST_DESCRIPTION(
"Test sync1 barrier with ACCELERATION_STRUCTURE_READ memory access."
"Ray query feature is not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkMemoryBarrier memory_barrier = vku::InitStructHelper();
memory_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
memory_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
vkt::Buffer buffer(*m_device, 32);
VkBufferMemoryBarrier buffer_barrier = vku::InitStructHelper();
buffer_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.buffer = buffer.handle();
buffer_barrier.size = VK_WHOLE_SIZE;
VkImageObj image(m_device);
image.Init(128, 128, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
ASSERT_TRUE(image.initialized());
VkImageMemoryBarrier image_barrier = vku::InitStructHelper();
image_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.image = image.handle();
image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_commandBuffer->begin();
// memory barrier
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-dstAccessMask-06257");
// buffer barrier
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-dstAccessMask-06257");
// image barrier
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdPipelineBarrier-dstAccessMask-06257");
vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, 0, 1, &memory_barrier, 1, &buffer_barrier, 1, &image_barrier);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, EventSync1AccessAccelerationStructureRayQueryDisabled) {
TEST_DESCRIPTION(
"Test sync1 event wait with ACCELERATION_STRUCTURE_READ memory access."
"Ray query feature is not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const vkt::Event event(*m_device);
VkMemoryBarrier memory_barrier = vku::InitStructHelper();
memory_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
memory_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
vkt::Buffer buffer(*m_device, 32);
VkBufferMemoryBarrier buffer_barrier = vku::InitStructHelper();
buffer_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
buffer_barrier.buffer = buffer.handle();
buffer_barrier.size = VK_WHOLE_SIZE;
VkImageObj image(m_device);
image.Init(128, 128, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
ASSERT_TRUE(image.initialized());
VkImageMemoryBarrier image_barrier = vku::InitStructHelper();
image_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.image = image.handle();
image_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_commandBuffer->begin();
// memory
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-dstAccessMask-06257");
// buffer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-dstAccessMask-06257");
// image
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-srcAccessMask-06257");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-dstAccessMask-06257");
m_commandBuffer->WaitEvents(1, &event.handle(), VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
1, &memory_barrier, 1, &buffer_barrier, 1, &image_barrier);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, DescriptorBindingUpdateAfterBindWithAccelerationStructure) {
TEST_DESCRIPTION("Validate acceleration structure descriptor writing.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkDescriptorSetLayoutBinding binding = {};
binding.binding = 0;
binding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_ALL;
binding.pImmutableSamplers = nullptr;
VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_create_info = vku::InitStructHelper();
flags_create_info.bindingCount = 1;
flags_create_info.pBindingFlags = &flags;
VkDescriptorSetLayoutCreateInfo create_info = vku::InitStructHelper(&flags_create_info);
create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
create_info.bindingCount = 1;
create_info.pBindings = &binding;
VkDescriptorSetLayout setLayout;
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingAccelerationStructureUpdateAfterBind-03570");
vk::CreateDescriptorSetLayout(device(), &create_info, nullptr, &setLayout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, MaxPerStageDescriptorAccelerationStructures) {
TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(accel_struct_props);
// Create one descriptor set layout holding (maxPerStageDescriptorAccelerationStructures + 1) bindings
// for the same shader stage
const uint32_t max_accel_structs = accel_struct_props.maxPerStageDescriptorAccelerationStructures;
if (max_accel_structs > 4096) {
GTEST_SKIP() << "maxPerStageDescriptorAccelerationStructures is too large";
} else if (max_accel_structs < 1) {
GTEST_SKIP() << "maxPerStageDescriptorAccelerationStructures is 1";
}
std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
dslb_vec.reserve(max_accel_structs);
for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
VkDescriptorSetLayoutBinding dslb = {};
dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
dslb.descriptorCount = 1;
dslb.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
dslb.binding = i;
dslb_vec.push_back(dslb);
}
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = dslb_vec.data();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
ASSERT_TRUE(ds_layout.initialized());
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03571");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03573");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, MaxPerStageDescriptorUpdateAfterBindAccelerationStructures) {
TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(accel_struct_props);
// Create one descriptor set layout with flag VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT holding
// (maxPerStageDescriptorUpdateAfterBindAccelerationStructures + 1) bindings for the same shader stage
const uint32_t max_accel_structs = accel_struct_props.maxPerStageDescriptorUpdateAfterBindAccelerationStructures;
if (max_accel_structs > 4096) {
GTEST_SKIP() << "maxPerStageDescriptorUpdateAfterBindAccelerationStructures is too large";
} else if (max_accel_structs < 1) {
GTEST_SKIP() << "maxPerStageDescriptorUpdateAfterBindAccelerationStructures is 1";
}
std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
dslb_vec.reserve(max_accel_structs);
for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
VkDescriptorSetLayoutBinding dslb = {};
dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
dslb.descriptorCount = 1;
dslb.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
dslb.binding = i;
dslb_vec.push_back(dslb);
}
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = dslb_vec.data();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
ASSERT_TRUE(ds_layout.initialized());
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, MaxDescriptorSetAccelerationStructures) {
TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(accel_struct_props);
// Create one descriptor set layout holding (maxDescriptorSetAccelerationStructures + 1) bindings
// in total for two different shader stage
const uint32_t max_accel_structs = accel_struct_props.maxDescriptorSetAccelerationStructures;
if (max_accel_structs > 4096) {
GTEST_SKIP() << "maxDescriptorSetAccelerationStructures is too large";
} else if (max_accel_structs < 1) {
GTEST_SKIP() << "maxDescriptorSetAccelerationStructures is 1";
}
std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
dslb_vec.reserve(max_accel_structs);
for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
VkDescriptorSetLayoutBinding dslb = {};
dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
dslb.descriptorCount = 1;
dslb.stageFlags = (i % 2) ? VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR : VK_SHADER_STAGE_CALLABLE_BIT_KHR;
dslb.binding = i;
dslb_vec.push_back(dslb);
}
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = dslb_vec.data();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
ASSERT_TRUE(ds_layout.initialized());
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03573");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03571");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, MaxDescriptorSetUpdateAfterBindAccelerationStructures) {
TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR than allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceAccelerationStructurePropertiesKHR accel_struct_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(accel_struct_props);
// Create one descriptor set layout with flag VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT holding
// (maxDescriptorSetUpdateAfterBindAccelerationStructures + 1) bindings in total for two different shader stage
const uint32_t max_accel_structs = accel_struct_props.maxDescriptorSetUpdateAfterBindAccelerationStructures;
if (max_accel_structs > 4096) {
GTEST_SKIP() << "maxDescriptorSetUpdateAfterBindAccelerationStructures is too large";
} else if (max_accel_structs < 1) {
GTEST_SKIP() << "maxDescriptorSetUpdateAfterBindAccelerationStructures is 1";
}
std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {};
dslb_vec.reserve(max_accel_structs);
for (uint32_t i = 0; i < max_accel_structs + 1; ++i) {
VkDescriptorSetLayoutBinding dslb = {};
dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
dslb.descriptorCount = 1;
dslb.stageFlags = (i % 2) ? VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR : VK_SHADER_STAGE_CALLABLE_BIT_KHR;
dslb.binding = i;
dslb_vec.push_back(dslb);
}
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
ds_layout_ci.bindingCount = dslb_vec.size();
ds_layout_ci.pBindings = dslb_vec.data();
vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci);
ASSERT_TRUE(ds_layout.initialized());
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03574");
m_errorMonitor->SetAllowedFailureMsg("VUID-VkPipelineLayoutCreateInfo-descriptorType-03572");
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BeginQueryQueryPoolType) {
TEST_DESCRIPTION("Test CmdBeginQuery with invalid queryPool queryType");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddOptionalExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddOptionalExtensions(VK_NV_RAY_TRACING_EXTENSION_NAME);
AddOptionalExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework());
const bool khr_acceleration_structure = IsExtensionsEnabled(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
const bool nv_ray_tracing = IsExtensionsEnabled(VK_NV_RAY_TRACING_EXTENSION_NAME);
const bool ext_transform_feedback = IsExtensionsEnabled(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
const bool rt_maintenance_1 = IsExtensionsEnabled(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
if (!khr_acceleration_structure && !nv_ray_tracing) {
GTEST_SKIP() << "Extensions " << VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME << " and " << VK_NV_RAY_TRACING_EXTENSION_NAME
<< " are not supported.";
}
RETURN_IF_SKIP(InitState());
if (khr_acceleration_structure) {
auto cmd_begin_query = [this, ext_transform_feedback](VkQueryType query_type, auto vuid_begin_query,
auto vuid_begin_query_indexed) {
vkt::QueryPool query_pool(*m_device, query_type, 1);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid_begin_query);
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool.handle(), 0, 0);
m_errorMonitor->VerifyFound();
if (ext_transform_feedback) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid_begin_query_indexed);
vk::CmdBeginQueryIndexedEXT(m_commandBuffer->handle(), query_pool.handle(), 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
};
cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-04728",
"VUID-vkCmdBeginQueryIndexedEXT-queryType-04728");
cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-04728",
"VUID-vkCmdBeginQueryIndexedEXT-queryType-04728");
if (rt_maintenance_1) {
cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, "VUID-vkCmdBeginQuery-queryType-06741",
"VUID-vkCmdBeginQueryIndexedEXT-queryType-06741");
cmd_begin_query(VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
"VUID-vkCmdBeginQuery-queryType-06741", "VUID-vkCmdBeginQueryIndexedEXT-queryType-06741");
}
}
if (nv_ray_tracing) {
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV, 1);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBeginQuery-queryType-04729");
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool.handle(), 0, 0);
m_errorMonitor->VerifyFound();
if (ext_transform_feedback) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBeginQueryIndexedEXT-queryType-04729");
vk::CmdBeginQueryIndexedEXT(m_commandBuffer->handle(), query_pool.handle(), 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
}
}
TEST_F(NegativeRayTracing, CopyUnboundAccelerationStructure) {
TEST_DESCRIPTION("Test CmdCopyQueryPoolResults with unsupported query type");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas_no_mem = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas_no_mem->SetDeviceBufferInitNoMem(true);
blas_no_mem->Build();
auto valid_blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
valid_blas->Build();
VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
copy_info.src = blas_no_mem->handle();
copy_info.dst = valid_blas->handle();
copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03737");
vk::CmdCopyAccelerationStructureKHR(m_commandBuffer->handle(), &copy_info);
m_errorMonitor->VerifyFound();
copy_info.src = valid_blas->handle();
copy_info.dst = blas_no_mem->handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03738");
vk::CmdCopyAccelerationStructureKHR(m_commandBuffer->handle(), &copy_info);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, CmdCopyUnboundAccelerationStructure) {
TEST_DESCRIPTION("Test CmdCopyAccelerationStructureKHR with buffers not bound to memory");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
// Init a non host visible buffer
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 4096;
buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements = buffer.memory_requirements();
VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
memory_alloc.allocationSize = memory_requirements.size;
ASSERT_TRUE(
m_device->phy().set_memory_type(memory_requirements.memoryTypeBits, &memory_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
vkt::DeviceMemory device_memory(*m_device, memory_alloc);
ASSERT_TRUE(device_memory.initialized());
vk::BindBufferMemory(m_device->handle(), buffer.handle(), device_memory.handle(), 0);
auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas->SetDeviceBuffer(std::move(buffer));
blas->Build();
auto blas_no_mem = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas_no_mem->SetDeviceBufferInitNoMem(true);
blas_no_mem->Build();
auto blas_host_mem = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas_host_mem->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
blas_host_mem->Build();
VkCopyAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
copy_info.src = blas_no_mem->handle();
copy_info.dst = blas->handle();
copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03737");
vk::CmdCopyAccelerationStructureKHR(m_commandBuffer->handle(), &copy_info);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
copy_info.src = blas->handle();
copy_info.dst = blas_no_mem->handle();
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureKHR-buffer-03738");
vk::CmdCopyAccelerationStructureKHR(m_commandBuffer->handle(), &copy_info);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
copy_info.src = blas->handle();
copy_info.dst = blas_host_mem->handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCopyAccelerationStructureKHR-buffer-03727");
vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
m_errorMonitor->VerifyFound();
copy_info.src = blas_host_mem->handle();
copy_info.dst = blas->handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCopyAccelerationStructureKHR-buffer-03728");
vk::CopyAccelerationStructureKHR(device(), VK_NULL_HANDLE, &copy_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CmdCopyMemoryToAccelerationStructure) {
TEST_DESCRIPTION("Validate CmdCopyMemoryToAccelerationStructureKHR with dst buffer not bound to memory");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
if (IsPlatformMockICD()) {
GTEST_SKIP() << "Test not supported by MockICD";
}
RETURN_IF_SKIP(InitState());
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer src_buffer(*m_device, 4096, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 1024;
buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
vkt::Buffer dst_buffer(*m_device, buffer_ci, vkt::no_mem);
auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 0);
blas->SetDeviceBuffer(std::move(dst_buffer));
blas->Build();
VkCopyMemoryToAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
copy_info.src.deviceAddress = src_buffer.address();
copy_info.dst = blas->handle();
copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;
// Acceleration structure buffer is not bound to memory
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyMemoryToAccelerationStructureKHR-buffer-03745");
m_commandBuffer->begin();
vk::CmdCopyMemoryToAccelerationStructureKHR(m_commandBuffer->handle(), &copy_info);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructureKHR) {
TEST_DESCRIPTION("Validate buffers used in vkBuildAccelerationStructureKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
// Init a non host visible buffer
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 4096;
buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements = non_host_visible_buffer.memory_requirements();
VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
memory_alloc.allocationSize = memory_requirements.size;
ASSERT_TRUE(
m_device->phy().set_memory_type(memory_requirements.memoryTypeBits, &memory_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
vkt::DeviceMemory device_memory(*m_device, memory_alloc);
ASSERT_TRUE(device_memory.initialized());
vk::BindBufferMemory(m_device->handle(), non_host_visible_buffer.handle(), device_memory.handle(), 0);
vkt::Buffer host_buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(non_host_visible_buffer));
// .dstAccelerationStructure buffer is not bound to host visible memory
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03722");
blas.BuildHost();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructureModeUpdate) {
TEST_DESCRIPTION("Validate buffers used in vkBuildAccelerationStructureKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(Init());
auto host_cached_blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
host_cached_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
host_cached_blas.SetSrcAS(vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096));
host_cached_blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03667");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03758");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03760");
host_cached_blas.BuildHost();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, WriteAccelerationStructureMemory) {
TEST_DESCRIPTION("Test memory in vkWriteAccelerationStructuresPropertiesKHR is host visible");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(Init());
// Init a non host visible buffer
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 4096;
buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements = non_host_visible_buffer.memory_requirements();
VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
memory_alloc.allocationSize = memory_requirements.size;
ASSERT_TRUE(
m_device->phy().set_memory_type(memory_requirements.memoryTypeBits, &memory_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
vkt::DeviceMemory device_memory(*m_device, memory_alloc);
ASSERT_TRUE(device_memory.initialized());
vk::BindBufferMemory(m_device->handle(), non_host_visible_buffer.handle(), device_memory.handle(), 0);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(non_host_visible_buffer));
// .dstAccelerationStructure buffer is not bound to host visible memory
m_errorMonitor->SetAllowedFailureMsg("VUID-vkBuildAccelerationStructuresKHR-pInfos-03722");
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
blas.BuildHost();
m_errorMonitor->VerifyFound();
std::vector<uint32_t> data(4096);
// .dstAccelerationStructure buffer is not bound to host visible memory
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-buffer-03733");
vk::WriteAccelerationStructuresPropertiesKHR(device(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data.size(), data.data(),
data.size());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CopyMemoryToAccelerationStructureHostAddress) {
TEST_DESCRIPTION("vkCopyMemoryToAccelerationStructureKHR but the hostAddress is not aligned to 16.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
RETURN_IF_SKIP(Init());
auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, 4096);
blas->Build();
VkDeviceOrHostAddressConstKHR output_data;
output_data.hostAddress = reinterpret_cast<void *>(0x00000021);
VkCopyMemoryToAccelerationStructureInfoKHR info = vku::InitStructHelper();
info.dst = blas->handle();
info.src = output_data;
info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCopyMemoryToAccelerationStructureKHR-pInfo-03750");
vk::CopyMemoryToAccelerationStructureKHR(device(), VK_NULL_HANDLE, &info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CopyMemoryToAsBuffer) {
TEST_DESCRIPTION("Test invalid buffer used in vkCopyMemoryToAccelerationStructureKHR.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
RETURN_IF_SKIP(Init());
// Init a non host visible buffer
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 4096;
buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
vkt::Buffer non_host_visible_buffer(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements memory_requirements = non_host_visible_buffer.memory_requirements();
VkMemoryAllocateInfo memory_alloc = vku::InitStructHelper();
memory_alloc.allocationSize = memory_requirements.size;
ASSERT_TRUE(
m_device->phy().set_memory_type(memory_requirements.memoryTypeBits, &memory_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
vkt::DeviceMemory device_memory(*m_device, memory_alloc);
ASSERT_TRUE(device_memory.initialized());
vk::BindBufferMemory(m_device->handle(), non_host_visible_buffer.handle(), device_memory.handle(), 0);
auto blas = vkt::as::blueprint::AccelStructSimpleOnHostBottomLevel(*m_device, buffer_ci.size);
blas->SetDeviceBuffer(std::move(non_host_visible_buffer));
blas->Build();
uint8_t output[4096];
uint8_t *aligned_output = reinterpret_cast<uint8_t *>(Align<uintptr_t>(reinterpret_cast<uintptr_t>(output), 16));
VkDeviceOrHostAddressConstKHR output_data;
output_data.hostAddress = aligned_output;
VkCopyMemoryToAccelerationStructureInfoKHR info = vku::InitStructHelper();
info.dst = blas->handle();
info.src = output_data;
info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;
// .dstAccelerationStructure buffer is not bound to host visible memory
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCopyMemoryToAccelerationStructureKHR-buffer-03730");
vk::CopyMemoryToAccelerationStructureKHR(device(), VK_NULL_HANDLE, &info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CreateAccelerationStructureKHR) {
TEST_DESCRIPTION("Validate acceleration structure creation.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkAccelerationStructureKHR as;
VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer buffer(*m_device, 4096,
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
as_create_info.buffer = buffer.handle();
as_create_info.createFlags = 0;
as_create_info.offset = 0;
as_create_info.size = 0;
as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
as_create_info.deviceAddress = 0;
VkBufferDeviceAddressInfo device_address_info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, NULL, buffer.handle()};
VkDeviceAddress device_address = vk::GetBufferDeviceAddressKHR(device(), &device_address_info);
// invalid buffer;
{
vkt::Buffer invalid_buffer(*m_device, 4096, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
invalid_as_create_info.buffer = invalid_buffer.handle();
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-buffer-03614");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
// invalid deviceAddress and flag;
{
VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
invalid_as_create_info.deviceAddress = device_address;
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-deviceAddress-03612");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
invalid_as_create_info.deviceAddress = 0;
invalid_as_create_info.createFlags = VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR;
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-createFlags-parameter");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
// invalid size and offset;
{
VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
invalid_as_create_info.size = 4097; // buffer size is 4096
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-offset-03616");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
// invalid sType;
{
VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
invalid_as_create_info.sType = VK_STRUCTURE_TYPE_MAX_ENUM;
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-sType-sType");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
// invalid type;
{
VkAccelerationStructureCreateInfoKHR invalid_as_create_info = as_create_info;
invalid_as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR;
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
"VUID-VkAccelerationStructureCreateInfoKHR-type-parameter");
vk::CreateAccelerationStructureKHR(device(), &invalid_as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeRayTracing, CreateAccelerationStructureFeature) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddDisabledFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR);
VkAccelerationStructureKHR as;
VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
as_create_info.buffer = buffer.handle();
as_create_info.size = 4096;
as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreateAccelerationStructureKHR-accelerationStructure-03611");
vk::CreateAccelerationStructureKHR(device(), &as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-08934");
vk::DestroyAccelerationStructureKHR(device(), as, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CreateAccelerationStructureKHRReplayFeature) {
TEST_DESCRIPTION("Validate acceleration structure creation replay feature.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddDisabledFeature(vkt::Feature::accelerationStructureCaptureReplay);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer buffer(*m_device, 4096,
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
VkBufferDeviceAddressInfo device_address_info = vku::InitStructHelper();
device_address_info.buffer = buffer.handle();
VkDeviceAddress device_address = vk::GetBufferDeviceAddressKHR(device(), &device_address_info);
VkAccelerationStructureCreateInfoKHR as_create_info = vku::InitStructHelper();
as_create_info.buffer = buffer.handle();
as_create_info.createFlags = VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR;
as_create_info.offset = 0;
as_create_info.size = 0;
as_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
as_create_info.deviceAddress = device_address;
VkAccelerationStructureKHR as;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureCreateInfoKHR-createFlags-03613");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreateAccelerationStructureKHR-deviceAddress-03488");
vk::CreateAccelerationStructureKHR(device(), &as_create_info, nullptr, &as);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CmdTraceRaysKHR) {
TEST_DESCRIPTION("Validate vkCmdTraceRaysKHR.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Create ray tracing pipeline
VkPipeline raytracing_pipeline = VK_NULL_HANDLE;
{
const vkt::PipelineLayout empty_pipeline_layout(*m_device, {});
VkShaderObj rgen_shader(this, kRayTracingMinimalGlsl, VK_SHADER_STAGE_RAYGEN_BIT_KHR, SPV_ENV_VULKAN_1_2);
VkShaderObj chit_shader(this, kRayTracingMinimalGlsl, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, SPV_ENV_VULKAN_1_2);
const vkt::PipelineLayout pipeline_layout(*m_device, {});
std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages;
shader_stages[0] = vku::InitStructHelper();
shader_stages[0].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
shader_stages[0].module = chit_shader.handle();
shader_stages[0].pName = "main";
shader_stages[1] = vku::InitStructHelper();
shader_stages[1].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
shader_stages[1].module = rgen_shader.handle();
shader_stages[1].pName = "main";
std::array<VkRayTracingShaderGroupCreateInfoKHR, 1> shader_groups;
shader_groups[0] = vku::InitStructHelper();
shader_groups[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
shader_groups[0].generalShader = 1;
shader_groups[0].closestHitShader = VK_SHADER_UNUSED_KHR;
shader_groups[0].anyHitShader = VK_SHADER_UNUSED_KHR;
shader_groups[0].intersectionShader = VK_SHADER_UNUSED_KHR;
VkRayTracingPipelineCreateInfoKHR raytracing_pipeline_ci = vku::InitStructHelper();
raytracing_pipeline_ci.flags = 0;
raytracing_pipeline_ci.stageCount = static_cast<uint32_t>(shader_stages.size());
raytracing_pipeline_ci.pStages = shader_stages.data();
raytracing_pipeline_ci.pGroups = shader_groups.data();
raytracing_pipeline_ci.groupCount = shader_groups.size();
raytracing_pipeline_ci.layout = pipeline_layout.handle();
const VkResult result = vk::CreateRayTracingPipelinesKHR(m_device->handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, 1,
&raytracing_pipeline_ci, nullptr, &raytracing_pipeline);
ASSERT_EQ(VK_SUCCESS, result);
}
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.usage =
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR;
buffer_ci.size = 4096;
buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkt::Buffer buffer(*m_device, buffer_ci, vkt::no_mem);
VkMemoryRequirements mem_reqs;
vk::GetBufferMemoryRequirements(device(), buffer.handle(), &mem_reqs);
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
alloc_info.allocationSize = 4096;
vkt::DeviceMemory mem(*m_device, alloc_info);
vk::BindBufferMemory(device(), buffer.handle(), mem.handle(), 0);
VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(ray_tracing_properties);
const VkDeviceAddress device_address = buffer.address();
const VkStridedDeviceAddressRegionKHR stridebufregion = {device_address, ray_tracing_properties.shaderGroupHandleAlignment,
ray_tracing_properties.shaderGroupHandleAlignment};
m_commandBuffer->begin();
// Invalid stride multiplier
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.stride = (stridebufregion.size + 1) % stridebufregion.size;
if (invalid_stride.stride > 0) {
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-03694");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride,
100, 100, 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-03690");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion,
100, 100, 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-03686");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion,
100, 100, 1);
m_errorMonitor->VerifyFound();
}
}
// Invalid stride, greater than maxShaderGroupStride
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
uint32_t align = ray_tracing_properties.shaderGroupHandleSize;
invalid_stride.stride = static_cast<VkDeviceSize>(ray_tracing_properties.maxShaderGroupStride) +
(align - (ray_tracing_properties.maxShaderGroupStride % align));
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-04041");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride, 100,
100, 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-04035");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion, 100,
100, 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-stride-04029");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion, 100,
100, 1);
m_errorMonitor->VerifyFound();
}
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, raytracing_pipeline);
// buffer is missing flag VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
{
buffer_ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer buffer_missing_flag(*m_device, buffer_ci, vkt::no_mem);
vk::BindBufferMemory(device(), buffer_missing_flag.handle(), mem.handle(), 0);
const VkDeviceAddress device_address_missing_flag = buffer_missing_flag.address();
// buffer is missing flag VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
if (device_address_missing_flag == device_address) {
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
// This address is the same as the one from the first (valid) buffer, so no validation error
invalid_stride.deviceAddress = device_address_missing_flag;
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &invalid_stride, &stridebufregion, &stridebufregion, &stridebufregion,
100, 100, 1);
}
}
// pRayGenShaderBindingTable address range and stride are invalid
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.stride = 8128;
invalid_stride.size = 8128;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkStridedDeviceAddressRegionKHR-size-04631");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkStridedDeviceAddressRegionKHR-size-04632");
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &invalid_stride, &stridebufregion, &stridebufregion, &stridebufregion, 100,
100, 1);
m_errorMonitor->VerifyFound();
}
// pMissShaderBindingTable->deviceAddress == 0
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.deviceAddress = 0;
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &invalid_stride, &stridebufregion, &stridebufregion, 100,
100, 1);
m_errorMonitor->VerifyFound();
}
// pHitShaderBindingTable->deviceAddress == 0
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.deviceAddress = 0;
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &invalid_stride, &stridebufregion, 100,
100, 1);
}
// pCallableShaderBindingTable->deviceAddress == 0
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.deviceAddress = 0;
vk::CmdTraceRaysKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &stridebufregion, &invalid_stride, 100,
100, 1);
}
m_commandBuffer->end();
vk::DestroyPipeline(device(), raytracing_pipeline, nullptr);
}
TEST_F(NegativeRayTracing, CmdTraceRaysIndirectKHR) {
TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirectKHR.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkBufferCreateInfo buf_info = vku::InitStructHelper();
buf_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
buf_info.size = 4096;
buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer buffer(*m_device, buf_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info);
VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(ray_tracing_properties);
const VkDeviceAddress device_address = buffer.address();
VkStridedDeviceAddressRegionKHR stridebufregion = {};
stridebufregion.deviceAddress = device_address;
stridebufregion.stride = ray_tracing_properties.shaderGroupHandleAlignment;
stridebufregion.size = stridebufregion.stride;
m_commandBuffer->begin();
// Invalid stride multiplier
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
invalid_stride.stride = (stridebufregion.size + 1) % stridebufregion.size;
if (invalid_stride.stride > 0) {
// TODO - Create minimal ray tracing pipeline helper - remove all extra `08606`
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-03694");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &stridebufregion,
&invalid_stride, device_address);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-03690");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &invalid_stride,
&stridebufregion, device_address);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-03686");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &invalid_stride, &stridebufregion,
&stridebufregion, device_address);
m_errorMonitor->VerifyFound();
}
}
// Invalid stride, greater than maxShaderGroupStride
// Given the invalid stride computation, stride is likely to also be misaligned, so allow above errors
{
VkStridedDeviceAddressRegionKHR invalid_stride = stridebufregion;
if (ray_tracing_properties.maxShaderGroupStride ==
std::numeric_limits<decltype(ray_tracing_properties.maxShaderGroupStride)>::max()) {
printf("ray_tracing_properties.maxShaderGroupStride has maximum possible value, skipping related tests\n");
} else {
invalid_stride.stride = ray_tracing_properties.maxShaderGroupStride + 1;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-04041");
m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdTraceRaysIndirectKHR-stride-03694");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &stridebufregion,
&invalid_stride, device_address);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-04035");
m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdTraceRaysIndirectKHR-stride-03690");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &stridebufregion, &invalid_stride,
&stridebufregion, device_address);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirectKHR-stride-04029");
m_errorMonitor->SetAllowedFailureMsg("VUID-vkCmdTraceRaysIndirectKHR-stride-03686");
vk::CmdTraceRaysIndirectKHR(m_commandBuffer->handle(), &stridebufregion, &invalid_stride, &stridebufregion,
&stridebufregion, device_address);
m_errorMonitor->VerifyFound();
}
}
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, CmdTraceRaysIndirect2KHRFeatureDisabled) {
TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirect2KHR.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddDisabledFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkBufferCreateInfo buffer_info = vku::InitStructHelper();
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
buffer_info.size = 4096;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer buffer(*m_device, buffer_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info);
const VkDeviceAddress device_address = buffer.address();
m_commandBuffer->begin();
// No VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR was in the device create info pNext chain
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirect2KHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdTraceRaysIndirect2KHR-rayTracingPipelineTraceRaysIndirect2-03637");
vk::CmdTraceRaysIndirect2KHR(m_commandBuffer->handle(), device_address);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, CmdTraceRaysIndirect2KHRAddress) {
TEST_DESCRIPTION("Validate vkCmdTraceRaysIndirect2KHR.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkBufferCreateInfo buffer_info = vku::InitStructHelper();
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
buffer_info.size = 4096;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer buffer(*m_device, buffer_info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info);
const VkDeviceAddress device_address = buffer.address();
m_commandBuffer->begin();
// indirectDeviceAddress is not a multiple of 4
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirect2KHR-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysIndirect2KHR-indirectDeviceAddress-03634");
vk::CmdTraceRaysIndirect2KHR(m_commandBuffer->handle(), device_address + 1);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, AccelerationStructureVersionInfoKHR) {
TEST_DESCRIPTION("Validate VkAccelerationStructureVersionInfoKHR.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkAccelerationStructureVersionInfoKHR valid_version = vku::InitStructHelper();
VkAccelerationStructureCompatibilityKHR compatablity;
uint8_t mode[] = {VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR};
valid_version.pVersionData = mode;
{
VkAccelerationStructureVersionInfoKHR invalid_version = valid_version;
invalid_version.sType = VK_STRUCTURE_TYPE_MAX_ENUM;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureVersionInfoKHR-sType-sType");
vk::GetDeviceAccelerationStructureCompatibilityKHR(device(), &invalid_version, &compatablity);
m_errorMonitor->VerifyFound();
}
{
VkAccelerationStructureVersionInfoKHR invalid_version = valid_version;
invalid_version.pVersionData = NULL;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureVersionInfoKHR-pVersionData-parameter");
vk::GetDeviceAccelerationStructureCompatibilityKHR(device(), &invalid_version, &compatablity);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeRayTracing, IndirectCmdBuildAccelerationStructuresKHR) {
TEST_DESCRIPTION("Validate acceleration structure indirect builds.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Command buffer indirect build
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresIndirectKHR-dstAccelerationStructure-03800");
blas.BuildCmdBufferIndirect(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, IndirectStridesMultiple) {
TEST_DESCRIPTION("pIndirectStrides not a multiple of 4.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetIndirectStride(13);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pIndirectStrides-03787");
blas.BuildCmdBufferIndirect(*m_commandBuffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, HostCmdBuildAccelerationStructuresKHR) {
TEST_DESCRIPTION("Validate acceleration structure indirect builds.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Host build
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-dstAccelerationStructure-03800");
blas.BuildHost();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, CmdBuildAccelerationStructuresKHR) {
TEST_DESCRIPTION("Validate acceleration structure building.");
AddOptionalExtensions(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
const bool index_type_uint8 = IsExtensionsEnabled(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);
VkPhysicalDeviceAccelerationStructurePropertiesKHR acc_struct_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(acc_struct_properties);
// Command buffer not in recording mode
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-commandBuffer-recording");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// dstAccelerationStructure == VK_NULL_HANDLE
{ // Command buffer build
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetDstAS(vkt::as::blueprint::AccelStructNull(*m_device));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03800");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
}
// Positive build tests
{
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.BuildCmdBuffer(m_commandBuffer->handle(), true);
m_commandBuffer->end();
}
{
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.BuildCmdBuffer(m_commandBuffer->handle(), false);
m_commandBuffer->end();
}
m_commandBuffer->begin();
// Invalid info count
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetInfoCount(0);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-infoCount-arraylength");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-infoCount-arraylength");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid pInfos
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetNullInfos(true);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-parameter");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid ppBuildRangeInfos
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetNullBuildRangeInfos(true);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-ppBuildRangeInfos-parameter");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// must be called outside renderpass
{
InitRenderTarget();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-renderpass");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->EndRenderPass();
m_errorMonitor->VerifyFound();
}
// Invalid flags
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-parameter");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-flags-parameter");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid dst buffer
{
auto buffer_ci =
vkt::Buffer::create_info(4096, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR);
vkt::Buffer invalid_buffer(*m_device, buffer_ci, vkt::no_mem);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(invalid_buffer));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03707");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid sType
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetInfo().sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-sType-sType");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-sType-sType");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid Type
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetType(VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03654");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03654");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
blas.SetType(VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-parameter");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-parameter");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Total number of triangles in all geometries superior to VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxPrimitiveCount
{
constexpr auto primitive_count = vvl::kU32Max;
// Check that primitive count is indeed superior to limit
if (primitive_count > acc_struct_properties.maxPrimitiveCount) {
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetPrimitiveCount(primitive_count);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03795");
blas.GetSizeInfo();
m_errorMonitor->VerifyFound();
}
}
// Total number of AABBs in all geometries superior to VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxPrimitiveCount
{
constexpr auto primitive_count = vvl::kU32Max;
// Check that primitive count is indeed superior to limit
if (primitive_count > acc_struct_properties.maxPrimitiveCount) {
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
blas.GetGeometries()[0].SetPrimitiveCount(primitive_count);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-type-03794");
blas.GetSizeInfo();
m_errorMonitor->VerifyFound();
}
}
// Invalid stride in pGeometry.geometry.aabbs (not a multiple of 8)
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
blas.GetGeometries()[0].SetStride(1);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03545");
blas.GetSizeInfo(false);
m_errorMonitor->VerifyFound();
}
// Invalid stride in ppGeometry.geometry.aabbs (not a multiple of 8)
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
blas.GetGeometries()[0].SetStride(1);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03545");
blas.GetSizeInfo(true);
m_errorMonitor->VerifyFound();
}
// Invalid stride in pGeometry.geometry.aabbs (superior to UINT32_MAX)
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
blas.GetGeometries()[0].SetStride(8ull * vvl::kU32Max);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03820");
blas.GetSizeInfo(false);
m_errorMonitor->VerifyFound();
}
// Invalid stride in ppGeometry.geometry.aabbs (superior to UINT32_MAX)
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB);
blas.GetGeometries()[0].SetStride(8ull * vvl::kU32Max);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryAabbsDataKHR-stride-03820");
blas.GetSizeInfo(true);
m_errorMonitor->VerifyFound();
}
// Invalid vertex stride
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetStride(VkDeviceSize(vvl::kU32Max) + 1);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03819");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03819");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Invalid index type
if (index_type_uint8) {
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesIndexType(VK_INDEX_TYPE_UINT8_EXT);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-indexType-03798");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// ppGeometries and pGeometries both valid pointer
{
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
std::vector<VkAccelerationStructureGeometryKHR> geometries;
for (const auto &geometry : blas.GetGeometries()) {
geometries.emplace_back(geometry.GetVkObj());
}
blas.GetInfo().pGeometries = geometries.data(); // .ppGeometries is set in .BuildCmdBuffer()
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788");
// computed scratch buffer size will be 0 since vkGetAccelerationStructureBuildSizesKHR fails
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03802");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Buffer is missing VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR usage flag
{
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer bad_usage_buffer(*m_device, 1024,
VK_BUFFER_USAGE_RAY_TRACING_BIT_NV | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &alloc_flags);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(bad_usage_buffer), 3);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Scratch data buffer is missing VK_BUFFER_USAGE_STORAGE_BUFFER_BIT usage flag
{
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
auto bad_scratch = std::make_shared<vkt::Buffer>(*m_device, 4096, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetScratchBuffer(std::move(bad_scratch));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
// Scratch data buffer is 0
{
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
// no VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT => scratch address will be set to 0
auto bad_scratch = std::make_shared<vkt::Buffer>(*m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetScratchBuffer(std::move(bad_scratch));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03802");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
}
// Partially disabled, see https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/6040
TEST_F(NegativeRayTracing, AccelerationStructuresOverlappingMemory) {
TEST_DESCRIPTION(
"Validate acceleration structure building when source/destination acceleration structures and scratch buffers overlap.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
constexpr size_t build_info_count = 3;
// All buffers used to back source/destination acceleration struct and scratch will be bound to this memory chunk
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
alloc_info.allocationSize = 8192;
vkt::DeviceMemory buffer_memory(*m_device, alloc_info);
#if 0
// Test overlapping scratch buffers
{
VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
scratch_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
scratch_buffer_ci.size = 4096;
scratch_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
std::vector<std::shared_ptr<vkt::Buffer>> scratch_buffers(build_info_count);
std::vector<vkt::as::BuildGeometryInfoKHR> build_infos;
for (auto &scratch_buffer : scratch_buffers) {
scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, scratch_buffer_ci, vkt::no_mem);
vk::BindBufferMemory(m_device->device(), scratch_buffer->handle(), buffer_memory.handle(), 0);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetScratchBuffer(std::move(scratch_buffer));
build_infos.emplace_back(std::move(blas));
}
// Since all the scratch buffers are bound to the same memory, 03704 will be triggered for each pair of elements in
// `build_infos`
for (size_t i = 0; i < binom<size_t>(build_info_count, 2); ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704");
}
m_commandBuffer->begin();
vkt::as::BuildAccelerationStructuresKHR( m_commandBuffer->handle(), build_infos);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
#endif
// Test overlapping destination acceleration structures
{
VkBufferCreateInfo dst_blas_buffer_ci = vku::InitStructHelper();
dst_blas_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
dst_blas_buffer_ci.size = 4096;
dst_blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
std::vector<vkt::as::BuildGeometryInfoKHR> build_infos;
for (auto &dst_blas_buffer : dst_blas_buffers) {
dst_blas_buffer.init_no_mem(*m_device, dst_blas_buffer_ci);
vk::BindBufferMemory(m_device->device(), dst_blas_buffer.handle(), buffer_memory.handle(), 0);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffer));
build_infos.emplace_back(std::move(blas));
}
// Since all the destination acceleration structures are bound to the same memory, 03702 will be triggered for each pair of
// elements in `build_infos`
for (size_t i = 0; i < binom<size_t>(build_info_count, 2); ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
}
m_commandBuffer->begin();
vkt::as::BuildAccelerationStructuresKHR(m_commandBuffer->handle(), build_infos);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
#if 0
// Test overlapping destination acceleration structure and scratch buffer
{
VkBufferCreateInfo dst_blas_buffer_ci = vku::InitStructHelper();
dst_blas_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
dst_blas_buffer_ci.size = 4096;
dst_blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
scratch_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
scratch_buffer_ci.size = 4096;
scratch_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
std::vector<std::shared_ptr<vkt::Buffer>> scratch_buffers(build_info_count);
std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
for (size_t i = 0; i < build_info_count; ++i) {
dst_blas_buffers[i].init_no_mem(*m_device, dst_blas_buffer_ci);
vk::BindBufferMemory(m_device->device(), dst_blas_buffers[i].handle(), buffer_memory.handle(), 0);
scratch_buffers[i] = std::make_shared<vkt::Buffer>();
scratch_buffers[i]->init_no_mem(*m_device, scratch_buffer_ci);
vk::BindBufferMemory(m_device->device(), scratch_buffers[i]->handle(), buffer_memory.handle(), 0);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffers[i]));
blas.GetDstAS()->SetSize(4096);
blas.SetScratchBuffer(std::move(scratch_buffers[i]));
blas_vec.emplace_back(std::move(blas));
}
// Since all the destination acceleration structures and scratch buffers are bound to the same memory, 03702, 03703 and
// 03704 will be triggered for each pair of elements in `build_infos`. 03703 will also be triggered for individual elements.
for (size_t i = 0; i < binom<size_t>(build_info_count, 2); ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03703");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704");
}
for (size_t i = 0; i < build_info_count; ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03703");
}
m_commandBuffer->begin();
vkt::as::BuildAccelerationStructuresKHR(m_commandBuffer->handle(), blas_vec);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
#endif
// Test overlapping source acceleration structure and destination acceleration structures
{
VkBufferCreateInfo blas_buffer_ci = vku::InitStructHelper();
blas_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
blas_buffer_ci.size = 4096;
blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
std::vector<vkt::Buffer> src_blas_buffers(build_info_count);
std::vector<vkt::Buffer> dst_blas_buffers(build_info_count);
std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
for (size_t i = 0; i < build_info_count; ++i) {
src_blas_buffers[i].init_no_mem(*m_device, blas_buffer_ci);
vk::BindBufferMemory(m_device->device(), src_blas_buffers[i].handle(), buffer_memory.handle(), 0);
dst_blas_buffers[i].init_no_mem(*m_device, blas_buffer_ci);
vk::BindBufferMemory(m_device->device(), dst_blas_buffers[i].handle(), buffer_memory.handle(), 0);
// 1st step: build destination acceleration struct
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(src_blas_buffers[i]));
blas.GetDstAS()->SetSize(4096);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
// Possible 2nd step: insert memory barrier on acceleration structure buffer
// => no need here since 2nd build call will not be executed by the driver
// 3rd step: set destination acceleration struct as source, create new destination acceleration struct with its
// underlying buffer bound to the same memory as the source acceleration struct, and build using update mode to trigger
// 03701
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetDstAS()->SetDeviceBuffer(std::move(dst_blas_buffers[i]));
blas_vec.emplace_back(std::move(blas));
}
// Since all the source and destination acceleration structures are bound to the same memory, 03701 and 03702 will be
// triggered for each pair of elements in `build_infos`, and 03668 for each element
for (size_t i = 0; i < binom<size_t>(build_info_count, 2); ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03701");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03702");
}
for (size_t i = 0; i < build_info_count; ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03668");
}
m_commandBuffer->begin();
vkt::as::BuildAccelerationStructuresKHR(m_commandBuffer->handle(), blas_vec);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
#if 0
// Test overlapping source acceleration structure and scratch buffer
{
VkBufferCreateInfo blas_buffer_ci = vku::InitStructHelper();
blas_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
blas_buffer_ci.size = 4096;
blas_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo scratch_buffer_ci = vku::InitStructHelper();
scratch_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
scratch_buffer_ci.size = 4096;
scratch_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
std::vector<vkt::Buffer> src_blas_buffers(build_info_count);
std::vector<std::shared_ptr<vkt::Buffer>> scratch_buffers(build_info_count);
std::vector<vkt::as::BuildGeometryInfoKHR> blas_vec;
for (size_t i = 0; i < build_info_count; ++i) {
src_blas_buffers[i].init_no_mem(*m_device, blas_buffer_ci);
vk::BindBufferMemory(m_device->device(), src_blas_buffers[i].handle(), buffer_memory.handle(), 0);
scratch_buffers[i] = std::make_shared<vkt::Buffer>();
scratch_buffers[i]->init_no_mem(*m_device, scratch_buffer_ci);
vk::BindBufferMemory(m_device->device(), scratch_buffers[i]->handle(), buffer_memory.handle(), 0);
// 1st step: build destination acceleration struct
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBuffer(std::move(src_blas_buffers[i]));
blas.GetDstAS()->SetSize(4096); // Do this to ensure dst accel struct buffer and scratch do overlap
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
m_commandBuffer->begin();
blas.BuildCmdBuffer( m_commandBuffer->handle());
m_commandBuffer->end();
// Possible 2nd step: insert memory barrier on acceleration structure buffer
// => no need here since 2nd build call will not be executed by the driver
// 3rd step: set destination acceleration struct as source, create new destination acceleration struct,
// bound scratch buffer to the same memory as the source acceleration struct, and build using update mode to trigger
// 03705
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.SetScratchBuffer(std::move(scratch_buffers[i]));
blas_vec.emplace_back(std::move(blas));
}
// Since all the source and destination acceleration structures are bound to the same memory, 03701 and 03702 will be
// triggered for each pair of elements in `build_infos`. 03705 will also be triggered for individual elements.
for (size_t i = 0; i < binom<size_t>(build_info_count, 2); ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03704");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03705");
}
for (size_t i = 0; i < build_info_count; ++i) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-scratchData-03705");
}
m_commandBuffer->begin();
vkt::as::BuildAccelerationStructuresKHR( m_commandBuffer->handle(), blas_vec);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
#endif
}
TEST_F(NegativeRayTracing, ObjInUseCmdBuildAccelerationStructureKHR) {
TEST_DESCRIPTION("Validate acceleration structure building tracks the objects used.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
m_default_queue->submit(*m_commandBuffer);
// This test used to destroy buffers used for building the acceleration structure,
// to see if there life span was correctly tracked.
// Following issue 6461, buffers associated to a device address are not tracked anymore, as it is impossible
// to track the "correct" one: there is not a 1 to 1 mapping between a buffer and a device address.
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02442");
vk::DestroyAccelerationStructureKHR(m_device->handle(), blas.GetDstAS()->handle(), nullptr);
m_errorMonitor->VerifyFound();
m_default_queue->wait();
}
TEST_F(NegativeRayTracing, CmdCopyAccelerationStructureToMemoryKHR) {
TEST_DESCRIPTION("Validate CmdCopyAccelerationStructureToMemoryKHR.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas->SetDeviceBufferInitNoMem(true);
blas->Build();
VkDeviceOrHostAddressKHR output_data;
output_data.deviceAddress = 256;
VkCopyAccelerationStructureToMemoryInfoKHR copy_info = vku::InitStructHelper();
copy_info.src = blas->handle();
copy_info.dst = output_data;
copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureToMemoryKHR-pInfo-03739");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyAccelerationStructureToMemoryKHR-None-03559");
vk::CmdCopyAccelerationStructureToMemoryKHR(*m_commandBuffer, &copy_info);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, CmdCopyMemoryToAccelerationStructureKHRInvalidSrcBuffer) {
TEST_DESCRIPTION("Validate vkCmdCopyMemoryToAccelerationStructureKHR.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096);
blas->Build();
VkCopyMemoryToAccelerationStructureInfoKHR copy_info = vku::InitStructHelper();
copy_info.src.deviceAddress = 256;
copy_info.dst = blas->handle();
copy_info.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyMemoryToAccelerationStructureKHR-pInfo-03742");
vk::CmdCopyMemoryToAccelerationStructureKHR(*m_commandBuffer, &copy_info);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, UpdateAccelerationStructureKHR) {
TEST_DESCRIPTION("Test for updating an acceleration structure without a srcAccelerationStructure");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
// Update acceleration structure, with .srcAccelerationStructure == VK_NULL_HANDLE
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-04630");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuffersAndBufferDeviceAddressesMapping) {
TEST_DESCRIPTION(
"Test that buffers and buffer device addresses mapping is correctly handled."
"Bound multiple buffers to the same memory so that they have the same buffer device address."
"Some buffers are valid for use in vkCmdBuildAccelerationStructuresKHR, others are not."
"Using buffer device addresses obtained from invalid buffers will result in a valid call to "
"vkCmdBuildAccelerationStructuresKHR,"
"because for this call to be valid, at least one buffer retrieved from the buffer device addresses must be valid."
"Valid and invalid buffers having the same address, the call is valid."
"Removing those valid buffers should cause calls to vkCmdBuildAccelerationStructuresKHR to be invalid,"
"as long as valid buffers are correctly removed from the internal buffer device addresses to buffers mapping.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Allocate common buffer memory
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
alloc_info.allocationSize = 4096;
vkt::DeviceMemory buffer_memory(*m_device, alloc_info);
// Create buffers, with correct and incorrect usage
constexpr size_t N = 3;
std::array<std::unique_ptr<vkt::as::BuildGeometryInfoKHR>, N> blas_vec{};
const VkBufferUsageFlags good_buffer_usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
const VkBufferUsageFlags bad_buffer_usage =
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buffer_ci.size = 4096;
buffer_ci.usage = good_buffer_usage;
for (size_t i = 0; i < N; ++i) {
if (i > 0) {
buffer_ci.usage = bad_buffer_usage;
}
vkt::Buffer vbo(*m_device, buffer_ci, vkt::no_mem);
vk::BindBufferMemory(device(), vbo.handle(), buffer_memory.handle(), 0);
vkt::Buffer ibo(*m_device, buffer_ci, vkt::no_mem);
vk::BindBufferMemory(device(), ibo.handle(), buffer_memory.handle(), 0);
// Those calls to vkGetBufferDeviceAddressKHR will internally record vbo and ibo device addresses
{
const VkDeviceAddress vbo_address = vbo.address();
const VkDeviceAddress ibo_address = ibo.address();
if (vbo_address != ibo_address) {
GTEST_SKIP()
<< "Bounding two buffers to the same memory location does not result in identical buffer device addresses";
}
}
blas_vec[i] = std::make_unique<vkt::as::BuildGeometryInfoKHR>(
vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
blas_vec[i]->GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vbo), 2);
blas_vec[i]->GetGeometries()[0].SetTrianglesDeviceIndexBuffer(std::move(ibo));
}
// The first series of calls to vkCmdBuildAccelerationStructuresKHR should succeed,
// since the first vbo and ibo do have the VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR flag.
// After deleting the valid vbo and ibo, calls are expected to fail.
for (size_t i = 0; i < N; ++i) {
m_commandBuffer->begin();
blas_vec[i]->BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
}
for (size_t i = 0; i < N; ++i) {
m_commandBuffer->begin();
if (i > 0) {
// for vbo
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
// for ibo
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673");
}
blas_vec[i]->VkCmdBuildAccelerationStructuresKHR(m_commandBuffer->handle());
if (i > 0) {
m_errorMonitor->VerifyFound();
}
m_commandBuffer->end();
blas_vec[i] = nullptr;
}
}
TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesHost) {
TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
// On host query with invalid query type
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
constexpr size_t stride = 1;
constexpr size_t data_size = sizeof(uint32_t) * stride;
uint8_t data[data_size];
// Incorrect query type
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06742");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION,
data_size, data, stride);
m_errorMonitor->VerifyFound();
// query types not known without extension
if (IsExtensionsEnabled(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME)) {
// queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, but stride is not a multiple of the size of VkDeviceSize
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06731");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR, data_size, data, stride);
m_errorMonitor->VerifyFound();
// queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR, but stride is not a
// multiple of the size of VkDeviceSize
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06733");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR,
data_size, data, stride);
m_errorMonitor->VerifyFound();
}
}
// TODO - 7230
// Crahses in BuildGeometryInfoKHR::GetSizeInfo calling vkGetAccelerationStructureBuildSizesKHR on Windows AMD and Android
TEST_F(NegativeRayTracing, DISABLED_WriteAccelerationStructuresPropertiesDevice) {
TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
// Incorrect query type
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryType-06742");
vk::CmdWriteAccelerationStructuresPropertiesKHR(m_commandBuffer->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_OCCLUSION, query_pool.handle(), 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, WriteAccelerationStructuresPropertiesMaintenance1Host) {
TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
RETURN_IF_SKIP(Init());
constexpr size_t stride = sizeof(VkDeviceSize);
constexpr size_t data_size = sizeof(VkDeviceSize) * stride;
uint8_t data[data_size];
// On host query with invalid query type
{
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
// Incorrect query type
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-06742");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(), VK_QUERY_TYPE_OCCLUSION,
data_size, data, stride);
m_errorMonitor->VerifyFound();
}
// On host query type with missing BLAS flag
{
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
// missing flag
blas.SetFlags(0);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data_size, data,
stride);
m_errorMonitor->VerifyFound();
}
// On host query type with invalid stride
{
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetDstAS()->SetDeviceBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03448");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, data_size, data, 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWriteAccelerationStructuresPropertiesKHR-queryType-03450");
vk::WriteAccelerationStructuresPropertiesKHR(m_device->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR, data_size, data,
1);
m_errorMonitor->VerifyFound();
}
}
// TODO - 7230
// Crahses in BuildGeometryInfoKHR::GetSizeInfo calling vkGetAccelerationStructureBuildSizesKHR on Windows AMD and Android
TEST_F(NegativeRayTracing, DISABLED_WriteAccelerationStructuresPropertiesMaintenance1Device) {
TEST_DESCRIPTION("Test queryType validation in vkCmdWriteAccelerationStructuresPropertiesKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::rayTracingMaintenance1);
RETURN_IF_SKIP(Init());
// On device query with invalid query type
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 1);
m_commandBuffer->begin();
blas.BuildCmdBuffer(m_commandBuffer->handle());
// Incorrect query type
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryType-06742");
vk::CmdWriteAccelerationStructuresPropertiesKHR(m_commandBuffer->handle(), 1, &blas.GetDstAS()->handle(),
VK_QUERY_TYPE_OCCLUSION, query_pool.handle(), 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresDeferredOperation) {
TEST_DESCRIPTION("Call vkBuildAccelerationStructuresKHR with a valid VkDeferredOperationKHR object");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-deferredOperation-parameter");
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetDeferredOp(CastFromUint64<VkDeferredOperationKHR>(0xdeadbeef));
blas.BuildHost();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidMode) {
TEST_DESCRIPTION("Build an acceleration structure with an invalid mode");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetMode(static_cast<VkBuildAccelerationStructureModeKHR>(42));
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-mode-04628");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryType) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list changing geometry type");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to geometry type
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0] = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03761");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryFlags) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"geometry flag");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to geometry flags
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetFlags(VK_GEOMETRY_OPAQUE_BIT_KHR);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03762");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesFormat) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"vertex format for the triangles");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
const VkFormat second_triangles_vertex_format = VK_FORMAT_R16G16B16_SFLOAT;
// Invalid update to triangles vertex format
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
vk::DeviceWaitIdle(*m_device);
m_commandBuffer->begin();
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetScratchBuffer(std::make_shared<vkt::Buffer>());
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetTrianglesVertexFormat(second_triangles_vertex_format);
VkFormatProperties vertex_format_props{};
vk::GetPhysicalDeviceFormatProperties(m_device->phy(), second_triangles_vertex_format, &vertex_format_props);
if (!(vertex_format_props.bufferFeatures & VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797");
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03763");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesFormatMissingFeature) {
TEST_DESCRIPTION("Use a triangles vertex format that misses the acceleration structure vertex buffer format feature");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
const VkFormat triangles_vertex_format = VK_FORMAT_R32_UINT;
VkFormatProperties vertex_format_props{};
vk::GetPhysicalDeviceFormatProperties(m_device->phy(), triangles_vertex_format, &vertex_format_props);
if (vertex_format_props.bufferFeatures & VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR) {
GTEST_SKIP()
<< "Hard coded vertex format has VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR, skipping test.";
}
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesVertexFormat(triangles_vertex_format);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexFormat-03797");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesMisalignedVertexStride) {
TEST_DESCRIPTION(
"Use a triangles vertex buffer stride that is not a multiple of the size in bytes of the smallest component of triangles "
"vertex format");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetStride(1);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureGeometryTrianglesDataKHR-vertexStride-03735");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesMisalignedVertexBufferAddress) {
TEST_DESCRIPTION(
"Use a triangles vertex buffer address that is not a multiple of the size in bytes of the smallest component of triangles "
"vertex format");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesVertexBufferDeviceAddress(1);
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03804"); // device address does not belong to a buffer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03711"); // misaligned device address
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesMaxVertex) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"maxVertex for triangles");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to triangles max vertex
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetTrianglesMaxVertex(666);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03764");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesIndexType) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different index "
"type for the triangles");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to triangles index type
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetTrianglesIndexType(VkIndexType::VK_INDEX_TYPE_UINT16);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03765");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometryTrianglesTransformData) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"pointer for the transform data");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to triangles transform data
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
vk::DeviceWaitIdle(*m_device);
m_commandBuffer->begin();
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetScratchBuffer(std::make_shared<vkt::Buffer>());
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetTrianglesTransformatData(666 * 16);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03766");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03808");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesVertexBufferNull) {
TEST_DESCRIPTION(
"Use a triangles vertex buffer specified referencing a null device address for an acceleration structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesVertexBufferDeviceAddress(0);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03804");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesIndexBufferNull) {
TEST_DESCRIPTION(
"Use a triangles vertex buffer specified referencing a null device address for an acceleration structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesIndexBufferDeviceAddress(0);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03806");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TrianglesIndexBufferInvalidAddress) {
TEST_DESCRIPTION("Use a triangles vertex buffer specified referencing a device address that is referencing no existing buffer");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesIndexBufferDeviceAddress(32);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03806");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, AabbBufferInvalidAddress) {
TEST_DESCRIPTION("Use a AABB buffer specified referencing a device address that referencing no existing buffer");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0] = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device);
blas.GetGeometries()[0].SetAABBsDeviceAddress(32);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03811");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructuresInvalidUpdatesToGeometry) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with triangles "
"transform data going from non NULL to NULL");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Invalid update to triangles transform data
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer transform_buffer(*m_device, 4096,
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.GetGeometries()[0].SetTrianglesTransformatData(transform_buffer.address());
blas.BuildCmdBuffer(m_commandBuffer->handle());
blas.SetSrcAS(blas.GetDstAS());
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetDstAS(vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, 4096));
blas.GetGeometries()[0].SetTrianglesTransformatData(0);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03767");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildNullGeometries) {
TEST_DESCRIPTION("Have a geometryCount > 0 but both pGeometries and ppGeometries be NULL");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(Init());
m_commandBuffer->begin();
// Build Bottom Level Acceleration Structure
auto blas =
std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
blas->SetNullGeometries(true);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788");
blas->GetSizeInfo();
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TransformBufferInvalidDeviceAddress) {
TEST_DESCRIPTION(
"Use a transform buffer specified with a device address that does not belong to an existing buffer for an acceleration "
"structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesTransformatData(16);
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03808");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TransformBufferInvalid) {
TEST_DESCRIPTION("Use a transform buffer whose memory has been freed for an acceleration structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
vkt::Buffer transform_buffer(*m_device, 4096,
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.GetGeometries()[0].SetTrianglesTransformatData(transform_buffer.address());
m_commandBuffer->begin();
blas.SetupBuild(*m_device, true);
transform_buffer.memory().destroy();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03809");
blas.VkCmdBuildAccelerationStructuresKHR(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, BuildAccelerationStructureMode) {
TEST_DESCRIPTION("Use invalid mode for vkBuildAccelerationStructureKHR");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::accelerationStructureHostCommands);
RETURN_IF_SKIP(Init());
vkt::Buffer host_buffer(*m_device, 4096, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnHostBottomLevel(*m_device);
blas.SetMode(static_cast<VkBuildAccelerationStructureModeKHR>(0xbadbeef0));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBuildAccelerationStructuresKHR-mode-04628");
blas.BuildHost();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeRayTracing, InstanceBufferBadAddress) {
TEST_DESCRIPTION("Use an invalid address for an instance buffer.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas =
std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
m_commandBuffer->begin();
blas->BuildCmdBuffer(*m_commandBuffer);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, blas);
m_commandBuffer->begin();
tlas.SetupBuild(*m_device, true);
tlas.GetGeometries()[0].SetInstanceDeviceAddress(0);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03813");
tlas.VkCmdBuildAccelerationStructuresKHR(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, InstanceBufferBadMemory) {
TEST_DESCRIPTION("Use an instance buffer whose memory has been destroyed for an acceleration structure build operation.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas =
std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
m_commandBuffer->begin();
blas->BuildCmdBuffer(*m_commandBuffer);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, blas);
m_commandBuffer->begin();
tlas.SetupBuild(*m_device, true);
tlas.GetGeometries()[0].GetInstance().buffer.memory().destroy();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03814");
tlas.VkCmdBuildAccelerationStructuresKHR(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, DynamicRayTracingPipelineStack) {
TEST_DESCRIPTION(
"Setup a ray tracing pipeline and acceleration structure with a dynamic ray tracing stack size, "
"but do not set size before tracing rays");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
vkt::rt::Pipeline pipeline(*this, m_device);
pipeline.SetRayGenShader(kRayTracingMinimalGlsl);
pipeline.AddDynamicState(VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR);
pipeline.Build();
m_commandBuffer->begin();
vk::CmdBindPipeline(*m_commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdTraceRaysKHR-None-09458");
vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt();
vk::CmdTraceRaysKHR(*m_commandBuffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt,
&trace_rays_sbt.callable_sbt, 1, 1, 1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
m_device->wait();
}
TEST_F(NegativeRayTracing, UpdatedFirstVertex) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"VkAccelerationStructureBuildRangeInfoKHR::firstVertex");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
m_commandBuffer->begin();
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetSrcAS(blas.GetDstAS());
// Create custom build ranges, with the default valid as a template, then somehow supply it?
auto build_range_infos = blas.GetDefaultBuildRangeInfos();
build_range_infos[0].firstVertex = 666;
blas.SetBuildRanges(build_range_infos);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-firstVertex-03770");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, UpdatedFirstPrimitiveCount) {
TEST_DESCRIPTION(
"Build a list of destination acceleration structures, then do an update build on that same list but with a different "
"VkAccelerationStructureBuildRangeInfoKHR::primitiveCount");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
m_commandBuffer->begin();
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetSrcAS(blas.GetDstAS());
// Create custom build ranges, with the default valid as a template, then somehow supply it?
auto build_range_infos = blas.GetDefaultBuildRangeInfos();
build_range_infos[0].primitiveCount = 0;
blas.SetBuildRanges(build_range_infos);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-primitiveCount-03769");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, ScratchBufferBadAddressSpaceOpBuild) {
TEST_DESCRIPTION("Use a scratch buffer that is too small for an acceleration structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
auto size_info = blas.GetSizeInfo(*m_device);
if (size_info.buildScratchSize <= 64) {
GTEST_SKIP() << "Need a big scratch size, skipping test.";
}
// Allocate buffer memory separately so that it can be large enough. Scratch buffer size will be smaller.
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
alloc_info.allocationSize = 4096;
vkt::DeviceMemory buffer_memory(*m_device, alloc_info);
VkBufferCreateInfo small_buffer_ci = vku::InitStructHelper();
small_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
small_buffer_ci.size = 64;
small_buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
auto scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, small_buffer_ci, vkt::no_mem);
scratch_buffer->bind_memory(buffer_memory, 0);
m_commandBuffer->begin();
blas.SetScratchBuffer(scratch_buffer);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03671");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, ScratchBufferBadAddressSpaceOpUpdate) {
TEST_DESCRIPTION("Use a scratch buffer that is too small for an acceleration structure update operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR);
auto size_info = blas.GetSizeInfo();
if (size_info.updateScratchSize <= 64) {
GTEST_SKIP() << "Update scratch size too small, skipping test.";
}
// Allocate buffer memory separately so that it can be large enough. Scratch buffer size will be smaller.
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
auto scratch_buffer =
std::make_shared<vkt::Buffer>(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc_flags);
m_commandBuffer->begin();
blas.BuildCmdBuffer(*m_commandBuffer);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
m_commandBuffer->begin();
blas.SetScratchBuffer(scratch_buffer);
blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR);
blas.SetSrcAS(blas.GetDstAS());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03672");
blas.BuildCmdBuffer(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, ScratchBufferBadMemory) {
TEST_DESCRIPTION("Use a scratch buffer whose memory has been destroyed for an acceleration structure build operation");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
// Allocate buffer memory separately so that it can be large enough. Scratch buffer size will be smaller.
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper(&alloc_flags);
alloc_info.allocationSize = 4096;
vkt::DeviceMemory buffer_memory(*m_device, alloc_info);
VkBufferCreateInfo small_buffer_ci = vku::InitStructHelper();
small_buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
small_buffer_ci.size = 4096;
small_buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
auto scratch_buffer = std::make_shared<vkt::Buffer>(*m_device, small_buffer_ci, vkt::no_mem);
scratch_buffer->bind_memory(buffer_memory, 0);
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
m_commandBuffer->begin();
blas.SetScratchBuffer(scratch_buffer);
blas.SetupBuild(*m_device, true);
buffer_memory.destroy();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03803");
blas.VkCmdBuildAccelerationStructuresKHR(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, DstAsTooSmall) {
TEST_DESCRIPTION("Try to perform a build on an acceleration structure that was created too small.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::rayQuery);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
m_commandBuffer->begin();
auto blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
blas.SetUpdateDstAccelStructSizeBeforeBuild(false);
blas.GetDstAS()->SetSize(1);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03675");
blas.BuildCmdBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
}
TEST_F(NegativeRayTracing, TooManyInstances) {
TEST_DESCRIPTION(
"Call vkGetAccelerationStructureBuildSizesKHR with pMaxPrimitiveCounts[0] > "
"VkPhysicalDeviceAccelerationStructurePropertiesKHR::maxInstanceCount");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::accelerationStructure);
RETURN_IF_SKIP(InitFrameworkForRayTracingTest());
RETURN_IF_SKIP(InitState());
auto blas =
std::make_shared<vkt::as::BuildGeometryInfoKHR>(vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device));
m_commandBuffer->begin();
blas->BuildCmdBuffer(*m_commandBuffer);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer();
vk::DeviceWaitIdle(*m_device);
auto tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, blas);
tlas.GetGeometries()[0].SetPrimitiveCount(std::numeric_limits<uint32_t>::max());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetAccelerationStructureBuildSizesKHR-pBuildInfo-03785");
tlas.GetSizeInfo();
m_errorMonitor->VerifyFound();
}