| /* |
| * Copyright (c) 2015-2025 The Khronos Group Inc. |
| * Copyright (c) 2015-2025 Valve Corporation |
| * Copyright (c) 2015-2025 LunarG, Inc. |
| * Copyright (c) 2015-2025 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_helper_nv.h" |
| #include "../framework/descriptor_helper.h" |
| #include <algorithm> |
| |
| void RayTracingTest::NvInitFrameworkForRayTracingTest(VkPhysicalDeviceFeatures2KHR *features2 /*= nullptr*/, |
| VkValidationFeaturesEXT *enabled_features /*= nullptr*/) { |
| AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_NV_RAY_TRACING_EXTENSION_NAME); |
| |
| RETURN_IF_SKIP(InitFramework(enabled_features)); |
| |
| if (features2) { |
| // extension enabled as dependency of RT extension |
| vk::GetPhysicalDeviceFeatures2KHR(Gpu(), features2); |
| } |
| } |
| |
| class NegativeRayTracingNV : public RayTracingTest { |
| public: |
| void OOBRayTracingShadersTestBodyNV(bool gpu_assisted); |
| }; |
| |
| void NegativeRayTracingNV::OOBRayTracingShadersTestBodyNV(bool gpu_assisted) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_NV_RAY_TRACING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
| AddOptionalExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); |
| VkValidationFeatureEnableEXT validation_feature_enables[] = {VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT}; |
| VkValidationFeatureDisableEXT validation_feature_disables[] = { |
| VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT, VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT, |
| VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT}; |
| VkValidationFeaturesEXT validation_features = vku::InitStructHelper(&kDisableMessageLimit); |
| validation_features.enabledValidationFeatureCount = 1; |
| validation_features.pEnabledValidationFeatures = validation_feature_enables; |
| validation_features.disabledValidationFeatureCount = 4; |
| validation_features.pDisabledValidationFeatures = validation_feature_disables; |
| RETURN_IF_SKIP(InitFramework(gpu_assisted ? (void *)&validation_features : (void *)&kDisableMessageLimit)); |
| bool descriptor_indexing = IsExtensionsEnabled(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); |
| |
| if (gpu_assisted && IsPlatformMockICD()) { |
| GTEST_SKIP() << "GPU-AV can't run on MockICD"; |
| } |
| |
| VkPhysicalDeviceFeatures2KHR features2 = vku::InitStructHelper(); |
| VkPhysicalDeviceDescriptorIndexingFeaturesEXT indexing_features = vku::InitStructHelper(); |
| if (descriptor_indexing) { |
| features2 = GetPhysicalDeviceFeatures2(indexing_features); |
| if (!indexing_features.runtimeDescriptorArray || !indexing_features.descriptorBindingPartiallyBound || |
| !indexing_features.descriptorBindingSampledImageUpdateAfterBind || |
| !indexing_features.descriptorBindingVariableDescriptorCount) { |
| printf("Not all descriptor indexing features supported, skipping descriptor indexing tests\n"); |
| descriptor_indexing = false; |
| } |
| } |
| |
| RETURN_IF_SKIP(InitState(nullptr, &features2)); |
| |
| VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(ray_tracing_properties); |
| if (ray_tracing_properties.maxTriangleCount == 0) { |
| GTEST_SKIP() << "Did not find required ray tracing properties"; |
| } |
| |
| vkt::Queue *ray_tracing_queue = m_default_queue; |
| uint32_t ray_tracing_queue_family_index = 0; |
| |
| // If supported, run on the compute only queue. |
| vkt::Queue *compute_only_queue = m_device->ComputeOnlyQueue(); |
| if (compute_only_queue) { |
| ray_tracing_queue = compute_only_queue; |
| ray_tracing_queue_family_index = compute_only_queue->family_index; |
| } |
| |
| vkt::CommandPool ray_tracing_command_pool(*m_device, ray_tracing_queue_family_index, |
| VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); |
| vkt::CommandBuffer ray_tracing_command_buffer(*m_device, ray_tracing_command_pool); |
| |
| constexpr std::array<VkAabbPositionsKHR, 1> aabbs = {{{-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f}}}; |
| |
| struct VkGeometryInstanceNV { |
| float transform[12]; |
| uint32_t instanceCustomIndex : 24; |
| uint32_t mask : 8; |
| uint32_t instanceOffset : 24; |
| uint32_t flags : 8; |
| uint64_t accelerationStructureHandle; |
| }; |
| |
| const VkDeviceSize aabb_buffer_size = sizeof(VkAabbPositionsKHR) * aabbs.size(); |
| vkt::Buffer aabb_buffer; |
| aabb_buffer.Init(*m_device, aabb_buffer_size, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps, nullptr, |
| vvl::make_span(&ray_tracing_queue_family_index, 1)); |
| |
| uint8_t *mapped_aabb_buffer_data = (uint8_t *)aabb_buffer.Memory().Map(); |
| std::memcpy(mapped_aabb_buffer_data, (uint8_t *)aabbs.data(), static_cast<std::size_t>(aabb_buffer_size)); |
| aabb_buffer.Memory().Unmap(); |
| |
| VkGeometryNV geometry = vku::InitStructHelper(); |
| geometry.geometryType = VK_GEOMETRY_TYPE_AABBS_NV; |
| geometry.geometry.triangles = vku::InitStructHelper(); |
| geometry.geometry.aabbs = vku::InitStructHelper(); |
| geometry.geometry.aabbs.aabbData = aabb_buffer; |
| geometry.geometry.aabbs.numAABBs = static_cast<uint32_t>(aabbs.size()); |
| geometry.geometry.aabbs.offset = 0; |
| geometry.geometry.aabbs.stride = static_cast<VkDeviceSize>(sizeof(VkAabbPositionsKHR)); |
| geometry.flags = 0; |
| |
| VkAccelerationStructureInfoNV bot_level_as_info = vku::InitStructHelper(); |
| bot_level_as_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_info.instanceCount = 0; |
| bot_level_as_info.geometryCount = 1; |
| bot_level_as_info.pGeometries = &geometry; |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = vku::InitStructHelper(); |
| bot_level_as_create_info.info = bot_level_as_info; |
| |
| vkt::AccelerationStructureNV bot_level_as(*m_device, bot_level_as_create_info); |
| |
| const std::array instances = { |
| VkGeometryInstanceNV{ |
| { |
| // clang-format off |
| 1.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| // clang-format on |
| }, |
| 0, |
| 0xFF, |
| 0, |
| VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV, |
| bot_level_as.OpaqueHandle(), |
| }, |
| }; |
| |
| VkDeviceSize instance_buffer_size = sizeof(instances[0]) * instances.size(); |
| vkt::Buffer instance_buffer; |
| instance_buffer.Init(*m_device, instance_buffer_size, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps, nullptr, |
| vvl::make_span(&ray_tracing_queue_family_index, 1)); |
| |
| uint8_t *mapped_instance_buffer_data = (uint8_t *)instance_buffer.Memory().Map(); |
| std::memcpy(mapped_instance_buffer_data, (uint8_t *)instances.data(), static_cast<std::size_t>(instance_buffer_size)); |
| instance_buffer.Memory().Unmap(); |
| |
| VkAccelerationStructureInfoNV top_level_as_info = vku::InitStructHelper(); |
| top_level_as_info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| top_level_as_info.instanceCount = 1; |
| top_level_as_info.geometryCount = 0; |
| |
| VkAccelerationStructureCreateInfoNV top_level_as_create_info = vku::InitStructHelper(); |
| top_level_as_create_info.info = top_level_as_info; |
| |
| vkt::AccelerationStructureNV top_level_as(*m_device, top_level_as_create_info); |
| |
| VkDeviceSize scratch_buffer_size = std::max(bot_level_as.BuildScratchMemoryRequirements().memoryRequirements.size, |
| top_level_as.BuildScratchMemoryRequirements().memoryRequirements.size); |
| vkt::Buffer scratch_buffer(*m_device, scratch_buffer_size, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| ray_tracing_command_buffer.Begin(); |
| |
| // Build bot level acceleration structure |
| vk::CmdBuildAccelerationStructureNV(ray_tracing_command_buffer, &bot_level_as.Info(), VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, scratch_buffer, 0); |
| |
| // Barrier to prevent using scratch buffer for top level build before bottom level build finishes |
| VkMemoryBarrier memory_barrier = vku::InitStructHelper(); |
| memory_barrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV; |
| memory_barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV; |
| vk::CmdPipelineBarrier(ray_tracing_command_buffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, |
| VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memory_barrier, 0, nullptr, 0, nullptr); |
| |
| // Build top level acceleration structure |
| vk::CmdBuildAccelerationStructureNV(ray_tracing_command_buffer, &top_level_as.Info(), instance_buffer, 0, VK_FALSE, |
| top_level_as, VK_NULL_HANDLE, scratch_buffer, 0); |
| |
| ray_tracing_command_buffer.End(); |
| |
| ray_tracing_queue->Submit(ray_tracing_command_buffer); |
| ray_tracing_queue->Wait(); |
| |
| vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView imageView = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| VkDeviceSize storage_buffer_size = 1024; |
| vkt::Buffer storage_buffer; |
| storage_buffer.Init(*m_device, storage_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps, nullptr, |
| vvl::make_span(&ray_tracing_queue_family_index, 1)); |
| |
| VkDeviceSize shader_binding_table_buffer_size = ray_tracing_properties.shaderGroupBaseAlignment * 4ull; |
| vkt::Buffer shader_binding_table_buffer; |
| shader_binding_table_buffer.Init(*m_device, shader_binding_table_buffer_size, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, |
| kHostVisibleMemProps, nullptr, vvl::make_span(&ray_tracing_queue_family_index, 1)); |
| |
| // Setup descriptors! |
| const VkShaderStageFlags kAllRayTracingStages = VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_ANY_HIT_BIT_NV | |
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV | VK_SHADER_STAGE_MISS_BIT_NV | |
| VK_SHADER_STAGE_INTERSECTION_BIT_NV | VK_SHADER_STAGE_CALLABLE_BIT_NV; |
| |
| void *layout_pnext = nullptr; |
| void *allocate_pnext = nullptr; |
| VkDescriptorPoolCreateFlags pool_create_flags = 0; |
| VkDescriptorSetLayoutCreateFlags layout_create_flags = 0; |
| VkDescriptorBindingFlags ds_binding_flags[3] = {}; |
| VkDescriptorSetLayoutBindingFlagsCreateInfo layout_createinfo_binding_flags[1] = {}; |
| if (descriptor_indexing) { |
| ds_binding_flags[0] = 0; |
| ds_binding_flags[1] = 0; |
| ds_binding_flags[2] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; |
| |
| layout_createinfo_binding_flags[0] = vku::InitStructHelper(); |
| layout_createinfo_binding_flags[0].bindingCount = 3; |
| layout_createinfo_binding_flags[0].pBindingFlags = ds_binding_flags; |
| layout_create_flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; |
| pool_create_flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; |
| layout_pnext = layout_createinfo_binding_flags; |
| } |
| |
| // Prepare descriptors |
| OneOffDescriptorSet ds(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1, kAllRayTracingStages, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, kAllRayTracingStages, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6, kAllRayTracingStages, nullptr}, |
| }, |
| layout_create_flags, layout_pnext, pool_create_flags); |
| |
| VkDescriptorSetVariableDescriptorCountAllocateInfo variable_count = vku::InitStructHelper(); |
| uint32_t desc_counts; |
| if (descriptor_indexing) { |
| layout_create_flags = 0; |
| pool_create_flags = 0; |
| ds_binding_flags[2] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT; |
| desc_counts = 6; // We'll reserve 8 spaces in the layout, but the descriptor will only use 6 |
| variable_count.descriptorSetCount = 1; |
| variable_count.pDescriptorCounts = &desc_counts; |
| allocate_pnext = &variable_count; |
| } |
| |
| OneOffDescriptorSet ds_variable(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1, kAllRayTracingStages, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, kAllRayTracingStages, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 8, kAllRayTracingStages, nullptr}, |
| }, |
| layout_create_flags, layout_pnext, pool_create_flags, allocate_pnext); |
| |
| VkAccelerationStructureNV top_level_as_handle = top_level_as; |
| VkWriteDescriptorSetAccelerationStructureNV write_descript_set_as = vku::InitStructHelper(); |
| write_descript_set_as.accelerationStructureCount = 1; |
| write_descript_set_as.pAccelerationStructures = &top_level_as_handle; |
| |
| VkDescriptorBufferInfo descriptor_buffer_info = {storage_buffer, 0, storage_buffer_size}; |
| VkDescriptorImageInfo descriptor_image_infos[6] = {}; |
| for (int i = 0; i < 6; i++) { |
| descriptor_image_infos[i] = {sampler, imageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; |
| } |
| |
| VkWriteDescriptorSet descriptor_writes[3] = {}; |
| descriptor_writes[0] = vku::InitStructHelper(&write_descript_set_as); |
| descriptor_writes[0].dstSet = ds.set_; |
| descriptor_writes[0].dstBinding = 0; |
| descriptor_writes[0].descriptorCount = 1; |
| descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; |
| |
| descriptor_writes[1] = vku::InitStructHelper(); |
| descriptor_writes[1].dstSet = ds.set_; |
| descriptor_writes[1].dstBinding = 1; |
| descriptor_writes[1].descriptorCount = 1; |
| descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| descriptor_writes[1].pBufferInfo = &descriptor_buffer_info; |
| |
| descriptor_writes[2] = vku::InitStructHelper(); |
| descriptor_writes[2].dstSet = ds.set_; |
| descriptor_writes[2].dstBinding = 2; |
| if (descriptor_indexing) { |
| descriptor_writes[2].descriptorCount = 5; // Intentionally don't write index 5 |
| } else { |
| descriptor_writes[2].descriptorCount = 6; |
| } |
| descriptor_writes[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
| descriptor_writes[2].pImageInfo = descriptor_image_infos; |
| vk::UpdateDescriptorSets(device(), 3, descriptor_writes, 0, NULL); |
| if (descriptor_indexing) { |
| descriptor_writes[0].dstSet = ds_variable.set_; |
| descriptor_writes[1].dstSet = ds_variable.set_; |
| descriptor_writes[2].dstSet = ds_variable.set_; |
| vk::UpdateDescriptorSets(device(), 3, descriptor_writes, 0, NULL); |
| } |
| |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&ds.layout_}); |
| const vkt::PipelineLayout pipeline_layout_variable(*m_device, {&ds_variable.layout_}); |
| |
| const auto SetImagesArrayLength = [](const std::string &shader_template, const std::string &length_str) { |
| const std::string to_replace = "IMAGES_ARRAY_LENGTH"; |
| |
| std::string result = shader_template; |
| auto position = result.find(to_replace); |
| assert(position != std::string::npos); |
| result.replace(position, to_replace.length(), length_str); |
| return result; |
| }; |
| |
| const std::string rgen_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : require |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 0) uniform accelerationStructureNV topLevelAS; |
| layout(set = 0, binding = 1, std430) buffer RayTracingSbo { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| layout(location = 0) rayPayloadNV vec3 payload; |
| layout(location = 3) callableDataNV vec3 callableData; |
| |
| void main() { |
| sbo.rgen_ran = 1; |
| |
| executeCallableNV(0, 3); |
| sbo.result1 = callableData.x; |
| |
| vec3 origin = vec3(0.0f, 0.0f, -2.0f); |
| vec3 direction = vec3(0.0f, 0.0f, 1.0f); |
| |
| traceNV(topLevelAS, gl_RayFlagsNoneNV, 0xFF, 0, 1, 0, origin, 0.001, direction, 10000.0, 0); |
| sbo.result2 = payload.x; |
| |
| traceNV(topLevelAS, gl_RayFlagsNoneNV, 0xFF, 0, 1, 0, origin, 0.001, -direction, 10000.0, 0); |
| sbo.result3 = payload.x; |
| |
| if (sbo.rgen_index > 0) { |
| // OOB here: |
| sbo.result3 = texelFetch(textures[sbo.rgen_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| |
| const std::string rgen_source = SetImagesArrayLength(rgen_source_template, "6"); |
| const std::string rgen_source_runtime = SetImagesArrayLength(rgen_source_template, ""); |
| |
| const std::string ahit_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : require |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 1, std430) buffer StorageBuffer { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| hitAttributeNV vec3 hitValue; |
| |
| layout(location = 0) rayPayloadInNV vec3 payload; |
| |
| void main() { |
| sbo.ahit_ran = 2; |
| |
| payload = vec3(0.1234f); |
| |
| if (sbo.ahit_index > 0) { |
| // OOB here: |
| payload.x = texelFetch(textures[sbo.ahit_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| const std::string ahit_source = SetImagesArrayLength(ahit_source_template, "6"); |
| const std::string ahit_source_runtime = SetImagesArrayLength(ahit_source_template, ""); |
| |
| const std::string chit_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : require |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 1, std430) buffer RayTracingSbo { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| layout(location = 0) rayPayloadInNV vec3 payload; |
| |
| hitAttributeNV vec3 attribs; |
| |
| void main() { |
| sbo.chit_ran = 3; |
| |
| payload = attribs; |
| if (sbo.chit_index > 0) { |
| // OOB here: |
| payload.x = texelFetch(textures[sbo.chit_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| const std::string chit_source = SetImagesArrayLength(chit_source_template, "6"); |
| const std::string chit_source_runtime = SetImagesArrayLength(chit_source_template, ""); |
| |
| const std::string miss_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : enable |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 1, std430) buffer RayTracingSbo { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| layout(location = 0) rayPayloadInNV vec3 payload; |
| |
| void main() { |
| sbo.miss_ran = 4; |
| |
| payload = vec3(1.0, 0.0, 0.0); |
| |
| if (sbo.miss_index > 0) { |
| // OOB here: |
| payload.x = texelFetch(textures[sbo.miss_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| const std::string miss_source = SetImagesArrayLength(miss_source_template, "6"); |
| const std::string miss_source_runtime = SetImagesArrayLength(miss_source_template, ""); |
| |
| const std::string intr_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : require |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 1, std430) buffer StorageBuffer { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| hitAttributeNV vec3 hitValue; |
| |
| void main() { |
| sbo.intr_ran = 5; |
| |
| hitValue = vec3(0.0f, 0.5f, 0.0f); |
| |
| reportIntersectionNV(1.0f, 0); |
| |
| if (sbo.intr_index > 0) { |
| // OOB here: |
| hitValue.x = texelFetch(textures[sbo.intr_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| const std::string intr_source = SetImagesArrayLength(intr_source_template, "6"); |
| const std::string intr_source_runtime = SetImagesArrayLength(intr_source_template, ""); |
| |
| const std::string call_source_template = R"(#version 460 |
| #extension GL_EXT_nonuniform_qualifier : require |
| #extension GL_EXT_samplerless_texture_functions : require |
| #extension GL_NV_ray_tracing : require |
| |
| layout(set = 0, binding = 1, std430) buffer StorageBuffer { |
| uint rgen_index; |
| uint ahit_index; |
| uint chit_index; |
| uint miss_index; |
| uint intr_index; |
| uint call_index; |
| |
| uint rgen_ran; |
| uint ahit_ran; |
| uint chit_ran; |
| uint miss_ran; |
| uint intr_ran; |
| uint call_ran; |
| |
| float result1; |
| float result2; |
| float result3; |
| } sbo; |
| layout(set = 0, binding = 2) uniform texture2D textures[IMAGES_ARRAY_LENGTH]; |
| |
| layout(location = 3) callableDataInNV vec3 callableData; |
| |
| void main() { |
| sbo.call_ran = 6; |
| |
| callableData = vec3(0.1234f); |
| |
| if (sbo.call_index > 0) { |
| // OOB here: |
| callableData.x = texelFetch(textures[sbo.call_index], ivec2(0, 0), 0).x; |
| } |
| } |
| )"; |
| const std::string call_source = SetImagesArrayLength(call_source_template, "6"); |
| const std::string call_source_runtime = SetImagesArrayLength(call_source_template, ""); |
| |
| struct TestCase { |
| const std::string &rgen_shader_source; |
| const std::string &ahit_shader_source; |
| const std::string &chit_shader_source; |
| const std::string &miss_shader_source; |
| const std::string &intr_shader_source; |
| const std::string &call_shader_source; |
| bool variable_length; |
| uint32_t rgen_index; |
| uint32_t ahit_index; |
| uint32_t chit_index; |
| uint32_t miss_index; |
| uint32_t intr_index; |
| uint32_t call_index; |
| const char *expected_error; |
| }; |
| |
| std::vector<TestCase> tests; |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 25, 0, 0, 0, 0, 0, |
| "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 0, 25, 0, 0, 0, 0, |
| "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 0, 0, 25, 0, 0, 0, |
| "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 0, 0, 0, 25, 0, 0, |
| "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 0, 0, 0, 0, 25, 0, |
| "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source, ahit_source, chit_source, miss_source, intr_source, call_source, false, 0, 0, 0, 0, 0, 25, |
| "Index of 25 used to index descriptor array of length 6."}); |
| |
| if (descriptor_indexing) { |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 25, 0, 0, 0, 0, 0, "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 25, 0, 0, 0, 0, "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 25, 0, 0, 0, "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 25, 0, 0, "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 25, 0, "Index of 25 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 0, 25, "Index of 25 used to index descriptor array of length 6."}); |
| |
| // For this group, 6 is less than max specified (max specified is 8) but more than actual specified (actual specified is 5) |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 6, 0, 0, 0, 0, 0, "Index of 6 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 6, 0, 0, 0, 0, "Index of 6 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 6, 0, 0, 0, "Index of 6 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 6, 0, 0, "Index of 6 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 6, 0, "Index of 6 used to index descriptor array of length 6."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 0, 6, "Index of 6 used to index descriptor array of length 6."}); |
| |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 5, 0, 0, 0, 0, 0, "Descriptor index 5 is uninitialized."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 5, 0, 0, 0, 0, "Descriptor index 5 is uninitialized."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 5, 0, 0, 0, "Descriptor index 5 is uninitialized."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 5, 0, 0, "Descriptor index 5 is uninitialized."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 5, 0, "Descriptor index 5 is uninitialized."}); |
| tests.push_back({rgen_source_runtime, ahit_source_runtime, chit_source_runtime, miss_source_runtime, intr_source_runtime, |
| call_source_runtime, true, 0, 0, 0, 0, 0, 5, "Descriptor index 5 is uninitialized."}); |
| } |
| |
| // Iteration 0 tests with no descriptor set bound (to sanity test "draw" validation). Iteration 1 |
| // tests what's in the test case vector. |
| for (const auto &test : tests) { |
| if (gpu_assisted) { |
| m_errorMonitor->SetDesiredError(test.expected_error); |
| } |
| |
| VkShaderObj rgen_shader(*m_device, test.rgen_shader_source.c_str(), VK_SHADER_STAGE_RAYGEN_BIT_NV); |
| VkShaderObj ahit_shader(*m_device, test.ahit_shader_source.c_str(), VK_SHADER_STAGE_ANY_HIT_BIT_NV); |
| VkShaderObj chit_shader(*m_device, test.chit_shader_source.c_str(), VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV); |
| VkShaderObj miss_shader(*m_device, test.miss_shader_source.c_str(), VK_SHADER_STAGE_MISS_BIT_NV); |
| VkShaderObj intr_shader(*m_device, test.intr_shader_source.c_str(), VK_SHADER_STAGE_INTERSECTION_BIT_NV); |
| VkShaderObj call_shader(*m_device, test.call_shader_source.c_str(), VK_SHADER_STAGE_CALLABLE_BIT_NV); |
| |
| VkPipelineShaderStageCreateInfo stage_create_infos[6] = {}; |
| stage_create_infos[0] = vku::InitStructHelper(); |
| stage_create_infos[0].stage = VK_SHADER_STAGE_RAYGEN_BIT_NV; |
| stage_create_infos[0].module = rgen_shader; |
| stage_create_infos[0].pName = "main"; |
| |
| stage_create_infos[1] = vku::InitStructHelper(); |
| stage_create_infos[1].stage = VK_SHADER_STAGE_ANY_HIT_BIT_NV; |
| stage_create_infos[1].module = ahit_shader; |
| stage_create_infos[1].pName = "main"; |
| |
| stage_create_infos[2] = vku::InitStructHelper(); |
| stage_create_infos[2].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV; |
| stage_create_infos[2].module = chit_shader; |
| stage_create_infos[2].pName = "main"; |
| |
| stage_create_infos[3] = vku::InitStructHelper(); |
| stage_create_infos[3].stage = VK_SHADER_STAGE_MISS_BIT_NV; |
| stage_create_infos[3].module = miss_shader; |
| stage_create_infos[3].pName = "main"; |
| |
| stage_create_infos[4] = vku::InitStructHelper(); |
| stage_create_infos[4].stage = VK_SHADER_STAGE_INTERSECTION_BIT_NV; |
| stage_create_infos[4].module = intr_shader; |
| stage_create_infos[4].pName = "main"; |
| |
| stage_create_infos[5] = vku::InitStructHelper(); |
| stage_create_infos[5].stage = VK_SHADER_STAGE_CALLABLE_BIT_NV; |
| stage_create_infos[5].module = call_shader; |
| stage_create_infos[5].pName = "main"; |
| |
| VkRayTracingShaderGroupCreateInfoNV group_create_infos[4] = {}; |
| group_create_infos[0] = vku::InitStructHelper(); |
| group_create_infos[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV; |
| group_create_infos[0].generalShader = 0; // rgen |
| group_create_infos[0].closestHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[0].anyHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[0].intersectionShader = VK_SHADER_UNUSED_NV; |
| |
| group_create_infos[1] = vku::InitStructHelper(); |
| group_create_infos[1].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV; |
| group_create_infos[1].generalShader = 3; // miss |
| group_create_infos[1].closestHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[1].anyHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[1].intersectionShader = VK_SHADER_UNUSED_NV; |
| |
| group_create_infos[2] = vku::InitStructHelper(); |
| group_create_infos[2].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV; |
| group_create_infos[2].generalShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[2].closestHitShader = 2; |
| group_create_infos[2].anyHitShader = 1; |
| group_create_infos[2].intersectionShader = 4; |
| |
| group_create_infos[3] = vku::InitStructHelper(); |
| group_create_infos[3].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV; |
| group_create_infos[3].generalShader = 5; // call |
| group_create_infos[3].closestHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[3].anyHitShader = VK_SHADER_UNUSED_NV; |
| group_create_infos[3].intersectionShader = VK_SHADER_UNUSED_NV; |
| |
| VkRayTracingPipelineCreateInfoNV pipeline_ci = vku::InitStructHelper(); |
| pipeline_ci.stageCount = 6; |
| pipeline_ci.pStages = stage_create_infos; |
| pipeline_ci.groupCount = 4; |
| pipeline_ci.pGroups = group_create_infos; |
| pipeline_ci.maxRecursionDepth = 2; |
| pipeline_ci.layout = test.variable_length ? pipeline_layout_variable : pipeline_layout; |
| |
| VkPipeline pipeline = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::CreateRayTracingPipelinesNV(*m_device, VK_NULL_HANDLE, 1, &pipeline_ci, nullptr, &pipeline)); |
| |
| std::vector<uint8_t> shader_binding_table_data; |
| shader_binding_table_data.resize(static_cast<std::size_t>(shader_binding_table_buffer_size), 0); |
| ASSERT_EQ(VK_SUCCESS, vk::GetRayTracingShaderGroupHandlesNV(*m_device, pipeline, 0, 4, |
| static_cast<std::size_t>(shader_binding_table_buffer_size), |
| shader_binding_table_data.data())); |
| |
| uint8_t *mapped_shader_binding_table_data = (uint8_t *)shader_binding_table_buffer.Memory().Map(); |
| std::memcpy(mapped_shader_binding_table_data, shader_binding_table_data.data(), shader_binding_table_data.size()); |
| shader_binding_table_buffer.Memory().Unmap(); |
| |
| ray_tracing_command_buffer.Begin(); |
| |
| vk::CmdBindPipeline(ray_tracing_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline); |
| |
| if (gpu_assisted) { |
| vk::CmdBindDescriptorSets(ray_tracing_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, |
| test.variable_length ? pipeline_layout_variable : pipeline_layout, 0, 1, |
| test.variable_length ? &ds_variable.set_ : &ds.set_, 0, nullptr); |
| } else { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-None-08600"); |
| } |
| |
| if (gpu_assisted) { |
| m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02462"); |
| m_errorMonitor->SetUnexpectedError("VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02458"); |
| // Need these values to pass mapped storage buffer checks |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupHandleSize * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupHandleSize * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupHandleSize * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupHandleSize * 3ull, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| } else { |
| // offset shall be multiple of shaderGroupBaseAlignment and stride of shaderGroupHandleSize |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 3ull, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| } |
| |
| ray_tracing_command_buffer.End(); |
| // Update the index of the texture that the shaders should read |
| uint32_t *mapped_storage_buffer_data = (uint32_t *)storage_buffer.Memory().Map(); |
| mapped_storage_buffer_data[0] = test.rgen_index; |
| mapped_storage_buffer_data[1] = test.ahit_index; |
| mapped_storage_buffer_data[2] = test.chit_index; |
| mapped_storage_buffer_data[3] = test.miss_index; |
| mapped_storage_buffer_data[4] = test.intr_index; |
| mapped_storage_buffer_data[5] = test.call_index; |
| mapped_storage_buffer_data[6] = 0; |
| mapped_storage_buffer_data[7] = 0; |
| mapped_storage_buffer_data[8] = 0; |
| mapped_storage_buffer_data[9] = 0; |
| mapped_storage_buffer_data[10] = 0; |
| mapped_storage_buffer_data[11] = 0; |
| storage_buffer.Memory().Unmap(); |
| |
| ray_tracing_queue->Submit(ray_tracing_command_buffer); |
| ray_tracing_queue->Wait(); |
| m_errorMonitor->VerifyFound(); |
| |
| if (gpu_assisted) { |
| mapped_storage_buffer_data = (uint32_t *)storage_buffer.Memory().Map(); |
| ASSERT_TRUE(mapped_storage_buffer_data[6] == 1); |
| ASSERT_TRUE(mapped_storage_buffer_data[7] == 2); |
| ASSERT_TRUE(mapped_storage_buffer_data[8] == 3); |
| ASSERT_TRUE(mapped_storage_buffer_data[9] == 4); |
| ASSERT_TRUE(mapped_storage_buffer_data[10] == 5); |
| ASSERT_TRUE(mapped_storage_buffer_data[11] == 6); |
| storage_buffer.Memory().Unmap(); |
| } else { |
| ray_tracing_command_buffer.Begin(); |
| vk::CmdBindPipeline(ray_tracing_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline); |
| vk::CmdBindDescriptorSets(ray_tracing_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, |
| test.variable_length ? pipeline_layout_variable : pipeline_layout, 0, 1, |
| test.variable_length ? &ds_variable.set_ : &ds.set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02462"); |
| VkDeviceSize stride_align = ray_tracing_properties.shaderGroupHandleSize; |
| VkDeviceSize invalid_max_stride = ray_tracing_properties.maxShaderGroupStride + |
| (stride_align - (ray_tracing_properties.maxShaderGroupStride % |
| stride_align)); // should be less than maxShaderGroupStride |
| VkDeviceSize invalid_stride = |
| ray_tracing_properties.shaderGroupHandleSize >> 1; // should be multiple of shaderGroupHandleSize |
| VkDeviceSize invalid_offset = |
| ray_tracing_properties.shaderGroupBaseAlignment >> 1; // should be multiple of shaderGroupBaseAlignment |
| |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, invalid_offset, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02465"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, invalid_stride, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02468"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, invalid_max_stride, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| // hit shader |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-hitShaderBindingOffset-02460"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, invalid_offset, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02464"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, invalid_stride, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02467"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| invalid_max_stride, shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| // miss shader |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02458"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, invalid_offset, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 2ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-missShaderBindingStride-02463"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, invalid_stride, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 2ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment, |
| ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-missShaderBindingStride-02466"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, invalid_max_stride, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| // raygenshader |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-raygenShaderBindingOffset-02456"); |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, invalid_offset, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/1); |
| |
| m_errorMonitor->VerifyFound(); |
| const auto &limits = m_device->Physical().limits_; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-width-02469"); |
| uint32_t invalid_width = limits.maxComputeWorkGroupCount[0] + 1; |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/invalid_width, /*height=*/1, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-height-02470"); |
| uint32_t invalid_height = limits.maxComputeWorkGroupCount[1] + 1; |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/invalid_height, /*depth=*/1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysNV-depth-02471"); |
| uint32_t invalid_depth = limits.maxComputeWorkGroupCount[2] + 1; |
| vk::CmdTraceRaysNV(ray_tracing_command_buffer, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 0ull, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment * 1ull, ray_tracing_properties.shaderGroupHandleSize, |
| shader_binding_table_buffer, ray_tracing_properties.shaderGroupBaseAlignment * 2ull, |
| ray_tracing_properties.shaderGroupHandleSize, shader_binding_table_buffer, |
| ray_tracing_properties.shaderGroupBaseAlignment, ray_tracing_properties.shaderGroupHandleSize, |
| /*width=*/1, /*height=*/1, /*depth=*/invalid_depth); |
| m_errorMonitor->VerifyFound(); |
| |
| ray_tracing_command_buffer.End(); |
| } |
| vk::DestroyPipeline(*m_device, pipeline, nullptr); |
| } |
| } |
| |
| TEST_F(NegativeRayTracingNV, ArrayOOBRayTracingShaders) { |
| TEST_DESCRIPTION( |
| "Core validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors for " |
| "ray tracing shaders."); |
| |
| OOBRayTracingShadersTestBodyNV(false); |
| } |
| |
| TEST_F(NegativeRayTracingNV, AccelerationStructureBindings) { |
| TEST_DESCRIPTION("Use more bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV than allowed"); |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| |
| VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(ray_tracing_props); |
| |
| RETURN_IF_SKIP(InitState()); |
| |
| uint32_t maxBlocks = ray_tracing_props.maxDescriptorSetAccelerationStructures; |
| if (maxBlocks > 4096) { |
| GTEST_SKIP() << "Too large of a maximum number of descriptor set acceleration structures, skipping tests"; |
| } |
| if (maxBlocks < 1) { |
| GTEST_SKIP() << "Test requires maxDescriptorSetAccelerationStructures >= 1"; |
| } |
| |
| std::vector<VkDescriptorSetLayoutBinding> dslb_vec = {}; |
| VkDescriptorSetLayoutBinding dslb = {}; |
| dslb.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; |
| dslb.descriptorCount = 1; |
| dslb.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
| |
| for (uint32_t i = 0; i <= maxBlocks; ++i) { |
| 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->SetDesiredError("VUID-VkPipelineLayoutCreateInfo-descriptorType-02381"); |
| vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateGeometry) { |
| TEST_DESCRIPTION("Validate acceleration structure geometries."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo(*m_device, 1024, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps); |
| vkt::Buffer ibo(*m_device, 1024, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps); |
| vkt::Buffer tbo(*m_device, 1024, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps); |
| vkt::Buffer aabbbo(*m_device, 1024, VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, kHostVisibleMemProps); |
| |
| VkBufferCreateInfo unbound_buffer_ci = vku::InitStructHelper(); |
| unbound_buffer_ci.size = 1024; |
| unbound_buffer_ci.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_NV; |
| vkt::Buffer unbound_buffer(*m_device, unbound_buffer_ci, vkt::no_mem); |
| |
| constexpr std::array vertices = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f}; |
| constexpr std::array<uint32_t, 3> indicies = {0, 1, 2}; |
| constexpr std::array aabbs = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; |
| constexpr std::array transforms = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; |
| |
| uint8_t *mapped_vbo_buffer_data = (uint8_t *)vbo.Memory().Map(); |
| std::memcpy(mapped_vbo_buffer_data, (uint8_t *)vertices.data(), sizeof(float) * vertices.size()); |
| |
| uint8_t *mapped_ibo_buffer_data = (uint8_t *)ibo.Memory().Map(); |
| std::memcpy(mapped_ibo_buffer_data, (uint8_t *)indicies.data(), sizeof(uint32_t) * indicies.size()); |
| |
| uint8_t *mapped_tbo_buffer_data = (uint8_t *)tbo.Memory().Map(); |
| std::memcpy(mapped_tbo_buffer_data, (uint8_t *)transforms.data(), sizeof(float) * transforms.size()); |
| |
| uint8_t *mapped_aabbbo_buffer_data = (uint8_t *)aabbbo.Memory().Map(); |
| std::memcpy(mapped_aabbbo_buffer_data, (uint8_t *)aabbs.data(), sizeof(float) * aabbs.size()); |
| |
| VkGeometryNV valid_geometry_triangles = vku::InitStructHelper(); |
| valid_geometry_triangles.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV; |
| valid_geometry_triangles.geometry.triangles = vku::InitStructHelper(); |
| valid_geometry_triangles.geometry.triangles.vertexData = vbo; |
| valid_geometry_triangles.geometry.triangles.vertexOffset = 0; |
| valid_geometry_triangles.geometry.triangles.vertexCount = 3; |
| valid_geometry_triangles.geometry.triangles.vertexStride = 12; |
| valid_geometry_triangles.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; |
| valid_geometry_triangles.geometry.triangles.indexData = ibo; |
| valid_geometry_triangles.geometry.triangles.indexOffset = 0; |
| valid_geometry_triangles.geometry.triangles.indexCount = 3; |
| valid_geometry_triangles.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; |
| valid_geometry_triangles.geometry.triangles.transformData = tbo; |
| valid_geometry_triangles.geometry.triangles.transformOffset = 0; |
| valid_geometry_triangles.geometry.aabbs = vku::InitStructHelper(); |
| |
| VkGeometryNV valid_geometry_aabbs = vku::InitStructHelper(); |
| valid_geometry_aabbs.geometryType = VK_GEOMETRY_TYPE_AABBS_NV; |
| valid_geometry_aabbs.geometry.triangles = vku::InitStructHelper(); |
| valid_geometry_aabbs.geometry.aabbs = vku::InitStructHelper(); |
| valid_geometry_aabbs.geometry.aabbs.aabbData = aabbbo; |
| valid_geometry_aabbs.geometry.aabbs.numAABBs = 1; |
| valid_geometry_aabbs.geometry.aabbs.offset = 0; |
| valid_geometry_aabbs.geometry.aabbs.stride = 24; |
| |
| const auto GetCreateInfo = [](const VkGeometryNV &geometry) { |
| VkAccelerationStructureCreateInfoNV as_create_info = vku::InitStructHelper(); |
| as_create_info.info = vku::InitStructHelper(); |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.instanceCount = 0; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| return as_create_info; |
| }; |
| |
| VkAccelerationStructureNV as; |
| |
| // Invalid vertex format. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexFormat = VK_FORMAT_R64_UINT; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-vertexFormat-02430"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex offset - not a multiple of component size. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-vertexOffset-02429"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexOffset = 12 * 1024; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-vertexOffset-02428"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid vertex buffer - no such buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.vertexData = VkBuffer(123456789); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-vertexData-parameter"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index offset - not a multiple of index size. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-indexOffset-02432"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexOffset = 2048; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-indexOffset-02431"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index count - must be 0 if type is VK_INDEX_TYPE_NONE_NV. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_NV; |
| geometry.geometry.triangles.indexData = VK_NULL_HANDLE; |
| geometry.geometry.triangles.indexCount = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-indexCount-02436"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid index data - must be VK_NULL_HANDLE if type is VK_INDEX_TYPE_NONE_NV. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_NV; |
| geometry.geometry.triangles.indexData = ibo; |
| geometry.geometry.triangles.indexCount = 0; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-indexData-02434"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Invalid transform offset - not a multiple of 16. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.transformOffset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-transformOffset-02438"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid transform offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_triangles; |
| geometry.geometry.triangles.transformOffset = 2048; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryTrianglesNV-transformOffset-02437"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid aabb offset - not a multiple of 8. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.offset = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryAABBNV-offset-02440"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid aabb offset - bigger than buffer. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.offset = 8 * 1024; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryAABBNV-offset-02439"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Invalid aabb stride - not a multiple of 8. |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.stride = 1; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryAABBNV-stride-02441"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // geometryType must be VK_GEOMETRY_TYPE_TRIANGLES_NV or VK_GEOMETRY_TYPE_AABBS_NV |
| { |
| VkGeometryNV geometry = valid_geometry_aabbs; |
| geometry.geometry.aabbs.stride = 1; |
| geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = GetCreateInfo(geometry); |
| m_errorMonitor->SetDesiredError("VUID-VkGeometryNV-geometryType-03503"); |
| m_errorMonitor->SetUnexpectedError("VUID-VkGeometryNV-geometryType-parameter"); |
| vk::CreateAccelerationStructureNV(device(), &as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateCreateAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure creation."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = vku::InitStructHelper(); |
| as_create_info.info = vku::InitStructHelper(); |
| |
| VkAccelerationStructureNV as = VK_NULL_HANDLE; |
| |
| // Top level can not have geometry |
| { |
| VkAccelerationStructureCreateInfoNV bad_top_level_create_info = as_create_info; |
| bad_top_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| bad_top_level_create_info.info.instanceCount = 0; |
| bad_top_level_create_info.info.geometryCount = 1; |
| bad_top_level_create_info.info.pGeometries = &geometry; |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-type-02425"); |
| vk::CreateAccelerationStructureNV(device(), &bad_top_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Bot level can not have instances |
| { |
| VkAccelerationStructureCreateInfoNV bad_bot_level_create_info = as_create_info; |
| bad_bot_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_bot_level_create_info.info.instanceCount = 1; |
| bad_bot_level_create_info.info.geometryCount = 0; |
| bad_bot_level_create_info.info.pGeometries = nullptr; |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-type-02426"); |
| vk::CreateAccelerationStructureNV(device(), &bad_bot_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Type must not be VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR |
| { |
| VkAccelerationStructureCreateInfoNV bad_bot_level_create_info = as_create_info; |
| bad_bot_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR; |
| bad_bot_level_create_info.info.instanceCount = 0; |
| bad_bot_level_create_info.info.geometryCount = 0; |
| bad_bot_level_create_info.info.pGeometries = nullptr; |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-type-04623"); |
| vk::CreateAccelerationStructureNV(device(), &bad_bot_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not prefer both fast trace and fast build |
| { |
| VkAccelerationStructureCreateInfoNV bad_flags_level_create_info = as_create_info; |
| bad_flags_level_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_flags_level_create_info.info.instanceCount = 0; |
| bad_flags_level_create_info.info.geometryCount = 1; |
| bad_flags_level_create_info.info.pGeometries = &geometry; |
| bad_flags_level_create_info.info.flags = |
| VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV; |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-flags-02592"); |
| vk::CreateAccelerationStructureNV(device(), &bad_flags_level_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not have geometry or instance for compacting |
| { |
| VkAccelerationStructureCreateInfoNV bad_compacting_as_create_info = as_create_info; |
| bad_compacting_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bad_compacting_as_create_info.info.instanceCount = 0; |
| bad_compacting_as_create_info.info.geometryCount = 1; |
| bad_compacting_as_create_info.info.pGeometries = &geometry; |
| bad_compacting_as_create_info.info.flags = 0; |
| bad_compacting_as_create_info.compactedSize = 1024; |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureCreateInfoNV-compactedSize-02421"); |
| vk::CreateAccelerationStructureNV(device(), &bad_compacting_as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not mix different geometry types into single bottom level acceleration structure |
| { |
| VkGeometryNV aabb_geometry = vku::InitStructHelper(); |
| aabb_geometry.geometryType = VK_GEOMETRY_TYPE_AABBS_NV; |
| aabb_geometry.geometry.triangles = vku::InitStructHelper(); |
| aabb_geometry.geometry.aabbs = vku::InitStructHelper(); |
| // Buffer contents do not matter for this test. |
| aabb_geometry.geometry.aabbs.aabbData = geometry.geometry.triangles.vertexData; |
| aabb_geometry.geometry.aabbs.numAABBs = 1; |
| aabb_geometry.geometry.aabbs.offset = 0; |
| aabb_geometry.geometry.aabbs.stride = 24; |
| |
| std::vector<VkGeometryNV> geometries = {geometry, aabb_geometry}; |
| |
| VkAccelerationStructureCreateInfoNV mix_geometry_types_as_create_info = as_create_info; |
| mix_geometry_types_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| mix_geometry_types_as_create_info.info.instanceCount = 0; |
| mix_geometry_types_as_create_info.info.geometryCount = static_cast<uint32_t>(geometries.size()); |
| mix_geometry_types_as_create_info.info.pGeometries = geometries.data(); |
| mix_geometry_types_as_create_info.info.flags = 0; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-type-02786"); |
| vk::CreateAccelerationStructureNV(device(), &mix_geometry_types_as_create_info, nullptr, &as); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateBindAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure binding."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = vku::InitStructHelper(); |
| as_create_info.info = vku::InitStructHelper(); |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| as_create_info.info.instanceCount = 0; |
| |
| vkt::AccelerationStructureNV as(*m_device, as_create_info, false); |
| |
| VkMemoryRequirements as_memory_requirements = as.MemoryRequirements().memoryRequirements; |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info = vku::InitStructHelper(); |
| as_bind_info.accelerationStructure = as; |
| |
| VkMemoryAllocateInfo as_memory_alloc = vku::InitStructHelper(); |
| as_memory_alloc.allocationSize = as_memory_requirements.size; |
| ASSERT_TRUE(m_device->Physical().SetMemoryType(as_memory_requirements.memoryTypeBits, &as_memory_alloc, 0)); |
| |
| // Can not bind already freed memory |
| { |
| VkDeviceMemory as_memory_freed = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_freed)); |
| vk::FreeMemory(device(), as_memory_freed, NULL); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_freed = as_bind_info; |
| as_bind_info_freed.memory = as_memory_freed; |
| as_bind_info_freed.memoryOffset = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-memory-parameter"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_freed); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Can not bind with bad alignment |
| if (as_memory_requirements.alignment > 1) { |
| VkMemoryAllocateInfo as_memory_alloc_bad_alignment = as_memory_alloc; |
| as_memory_alloc_bad_alignment.allocationSize += 1; |
| |
| VkDeviceMemory as_memory_bad_alignment = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc_bad_alignment, NULL, &as_memory_bad_alignment)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_alignment = as_bind_info; |
| as_bind_info_bad_alignment.memory = as_memory_bad_alignment; |
| as_bind_info_bad_alignment.memoryOffset = 1; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-03623"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_alignment); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), as_memory_bad_alignment, NULL); |
| } |
| |
| // Can not bind with offset outside the allocation |
| { |
| VkDeviceMemory as_memory_bad_offset = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_bad_offset)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_offset = as_bind_info; |
| as_bind_info_bad_offset.memory = as_memory_bad_offset; |
| as_bind_info_bad_offset.memoryOffset = |
| (as_memory_alloc.allocationSize + as_memory_requirements.alignment) & ~(as_memory_requirements.alignment - 1); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-03621"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), as_memory_bad_offset, NULL); |
| } |
| |
| // Can not bind with offset that doesn't leave enough size |
| { |
| VkDeviceSize offset = (as_memory_requirements.size - 1) & ~(as_memory_requirements.alignment - 1); |
| if (offset > 0 && (as_memory_requirements.size < (as_memory_alloc.allocationSize - as_memory_requirements.alignment))) { |
| VkDeviceMemory as_memory_bad_offset = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_bad_offset)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_offset = as_bind_info; |
| as_bind_info_bad_offset.memory = as_memory_bad_offset; |
| as_bind_info_bad_offset.memoryOffset = offset; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-size-03624"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), as_memory_bad_offset, NULL); |
| } |
| } |
| |
| // Can not bind with memory that has unsupported memory type |
| { |
| VkPhysicalDeviceMemoryProperties memory_properties = {}; |
| vk::GetPhysicalDeviceMemoryProperties(m_device->Physical(), &memory_properties); |
| |
| uint32_t supported_memory_type_bits = as_memory_requirements.memoryTypeBits; |
| uint32_t unsupported_mem_type_bits = ((1 << memory_properties.memoryTypeCount) - 1) & ~supported_memory_type_bits; |
| if (unsupported_mem_type_bits != 0) { |
| VkMemoryAllocateInfo as_memory_alloc_bad_type = as_memory_alloc; |
| ASSERT_TRUE(m_device->Physical().SetMemoryType(unsupported_mem_type_bits, &as_memory_alloc_bad_type, 0)); |
| |
| VkDeviceMemory as_memory_bad_type = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc_bad_type, NULL, &as_memory_bad_type)); |
| |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_bad_type = as_bind_info; |
| as_bind_info_bad_type.memory = as_memory_bad_type; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-memory-03622"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_bad_type); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), as_memory_bad_type, NULL); |
| } |
| } |
| |
| // Can not bind memory twice |
| { |
| vkt::AccelerationStructureNV as_twice(*m_device, as_create_info, false); |
| |
| VkDeviceMemory as_memory_twice_1 = VK_NULL_HANDLE; |
| VkDeviceMemory as_memory_twice_2 = VK_NULL_HANDLE; |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_twice_1)); |
| ASSERT_EQ(VK_SUCCESS, vk::AllocateMemory(device(), &as_memory_alloc, NULL, &as_memory_twice_2)); |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_twice_1 = as_bind_info; |
| VkBindAccelerationStructureMemoryInfoNV as_bind_info_twice_2 = as_bind_info; |
| as_bind_info_twice_1.accelerationStructure = as_twice; |
| as_bind_info_twice_2.accelerationStructure = as_twice; |
| as_bind_info_twice_1.memory = as_memory_twice_1; |
| as_bind_info_twice_2.memory = as_memory_twice_2; |
| |
| ASSERT_EQ(VK_SUCCESS, vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_twice_1)); |
| m_errorMonitor->SetDesiredError("VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-03620"); |
| vk::BindAccelerationStructureMemoryNV(device(), 1, &as_bind_info_twice_2); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), as_memory_twice_1, NULL); |
| vk::FreeMemory(device(), as_memory_twice_2, NULL); |
| } |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateWriteDescriptorSetAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure descriptor writing."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| OneOffDescriptorSet ds(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1, VK_SHADER_STAGE_RAYGEN_BIT_NV, nullptr}, |
| }); |
| |
| VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(); |
| descriptor_write.dstSet = ds.set_; |
| descriptor_write.dstBinding = 0; |
| descriptor_write.descriptorCount = 1; |
| descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; |
| |
| VkWriteDescriptorSetAccelerationStructureNV acc = vku::InitStructHelper(); |
| acc.accelerationStructureCount = 1; |
| VkAccelerationStructureCreateInfoNV top_level_as_create_info = vku::InitStructHelper(); |
| top_level_as_create_info.info = vku::InitStructHelper(); |
| top_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| top_level_as_create_info.info.instanceCount = 1; |
| top_level_as_create_info.info.geometryCount = 0; |
| |
| vkt::AccelerationStructureNV top_level_as(*m_device, top_level_as_create_info); |
| |
| acc.pAccelerationStructures = &top_level_as.handle(); |
| descriptor_write.pNext = &acc; |
| vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL); |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateCmdBuildAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure building."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = vku::InitStructHelper(); |
| bot_level_as_create_info.info = vku::InitStructHelper(); |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| vkt::AccelerationStructureNV bot_level_as(*m_device, bot_level_as_create_info); |
| |
| const vkt::Buffer bot_level_as_scratch = bot_level_as.CreateScratchBuffer(*m_device); |
| |
| // Command buffer must be in recording state |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-recording"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.Begin(); |
| |
| // Incompatible type |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_type = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_type.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV; |
| as_build_info_with_incompatible_type.instanceCount = 1; |
| as_build_info_with_incompatible_type.geometryCount = 0; |
| |
| // This is duplicated since it triggers one error for different types and one error for lower instance count - the |
| // build info is incompatible but still needs to be valid to get past the stateless checks. |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &as_build_info_with_incompatible_type, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Incompatible flags |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_flags = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_flags.flags = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV; |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &as_build_info_with_incompatible_flags, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Incompatible build size |
| VkGeometryNV geometry_with_more_vertices = geometry; |
| geometry_with_more_vertices.geometry.triangles.vertexCount += 1; |
| |
| VkAccelerationStructureInfoNV as_build_info_with_incompatible_geometry = bot_level_as_create_info.info; |
| as_build_info_with_incompatible_geometry.pGeometries = &geometry_with_more_vertices; |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-dst-02488"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &as_build_info_with_incompatible_geometry, VK_NULL_HANDLE, 0, VK_FALSE, |
| bot_level_as, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Scratch buffer too small |
| VkBufferCreateInfo too_small_scratch_buffer_info = vku::InitStructHelper(); |
| too_small_scratch_buffer_info.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_NV; |
| too_small_scratch_buffer_info.size = 1; |
| vkt::Buffer too_small_scratch_buffer(*m_device, too_small_scratch_buffer_info); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-update-02491"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, too_small_scratch_buffer, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Scratch buffer with offset too small |
| VkDeviceSize scratch_buffer_offset = 5; |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-update-02491"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, scratch_buffer_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| // Src must have been built before |
| vkt::AccelerationStructureNV bot_level_as_updated(*m_device, bot_level_as_create_info); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-update-02489"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_TRUE, |
| bot_level_as_updated, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Src must have been built before with the VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV flag |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-update-02490"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_TRUE, |
| bot_level_as_updated, bot_level_as, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // invalid scratch buffer (invalid usage) |
| VkBufferCreateInfo create_info = vku::InitStructHelper(); |
| create_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| const vkt::Buffer bot_level_as_invalid_scratch = bot_level_as.CreateScratchBuffer(*m_device, &create_info); |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-scratch-02781"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_invalid_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // invalid instance data. |
| m_errorMonitor->SetDesiredError("VUID-VkAccelerationStructureInfoNV-instanceData-02782"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, bot_level_as_invalid_scratch, 0, VK_FALSE, |
| bot_level_as, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // must be called outside renderpass |
| InitRenderTarget(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructureNV-renderpass"); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_command_buffer.EndRenderPass(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeRayTracingNV, ObjInUseCmdBuildAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure building tracks the objects used."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = vku::InitStructHelper(); |
| bot_level_as_create_info.info = vku::InitStructHelper(); |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| vkt::AccelerationStructureNV bot_level_as(*m_device, bot_level_as_create_info); |
| |
| const vkt::Buffer bot_level_as_scratch = bot_level_as.CreateScratchBuffer(*m_device); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, bot_level_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_command_buffer.End(); |
| m_default_queue->Submit(m_command_buffer); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkDestroyBuffer-buffer-00922"); |
| vk::DestroyBuffer(device(), ibo, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkDestroyBuffer-buffer-00922"); |
| vk::DestroyBuffer(device(), vbo, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkDestroyBuffer-buffer-00922"); |
| vk::DestroyBuffer(device(), bot_level_as_scratch, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkDestroyAccelerationStructureNV-accelerationStructure-03752"); |
| vk::DestroyAccelerationStructureNV(device(), bot_level_as, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_default_queue->Wait(); |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateGetAccelerationStructureHandle) { |
| TEST_DESCRIPTION("Validate acceleration structure handle querying."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = vku::InitStructHelper(); |
| bot_level_as_create_info.info = vku::InitStructHelper(); |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| // Not enough space for the handle |
| { |
| vkt::AccelerationStructureNV bot_level_as(*m_device, bot_level_as_create_info); |
| |
| uint64_t handle = 0; |
| m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureHandleNV-dataSize-02240"); |
| vk::GetAccelerationStructureHandleNV(device(), bot_level_as, sizeof(uint8_t), &handle); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // No memory bound to acceleration structure |
| { |
| vkt::AccelerationStructureNV bot_level_as(*m_device, bot_level_as_create_info, /*init_memory=*/false); |
| |
| uint64_t handle = 0; |
| m_errorMonitor->SetDesiredError("VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-02787"); |
| vk::GetAccelerationStructureHandleNV(device(), bot_level_as, sizeof(uint64_t), &handle); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeRayTracingNV, ValidateCmdCopyAccelerationStructure) { |
| TEST_DESCRIPTION("Validate acceleration structure copying."); |
| |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::Buffer vbo; |
| vkt::Buffer ibo; |
| VkGeometryNV geometry; |
| nv::rt::GetSimpleGeometryForAccelerationStructureTests(*m_device, &vbo, &ibo, &geometry); |
| |
| VkAccelerationStructureCreateInfoNV as_create_info = vku::InitStructHelper(); |
| as_create_info.info = vku::InitStructHelper(); |
| as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| as_create_info.info.instanceCount = 0; |
| as_create_info.info.geometryCount = 1; |
| as_create_info.info.pGeometries = &geometry; |
| |
| vkt::AccelerationStructureNV src_as(*m_device, as_create_info); |
| vkt::AccelerationStructureNV dst_as(*m_device, as_create_info); |
| vkt::AccelerationStructureNV dst_as_without_mem(*m_device, as_create_info, false); |
| |
| VkAccelerationStructureCreateInfoNV bot_level_as_create_info = vku::InitStructHelper(); |
| bot_level_as_create_info.info = vku::InitStructHelper(); |
| bot_level_as_create_info.info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV; |
| bot_level_as_create_info.info.instanceCount = 0; |
| bot_level_as_create_info.info.geometryCount = 1; |
| bot_level_as_create_info.info.pGeometries = &geometry; |
| |
| const vkt::Buffer bot_level_as_scratch = src_as.CreateScratchBuffer(*m_device); |
| |
| m_command_buffer.Begin(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-src-04963"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, src_as, |
| VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Command buffer must be in recording state |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-recording"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.Begin(); |
| |
| // Src must have been created with allow compaction flag |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-src-03411"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| // Dst must have been bound with memory |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-dst-07792"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as_without_mem, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| |
| m_errorMonitor->VerifyFound(); |
| |
| // mode must be VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR or VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-mode-03410"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR); |
| m_errorMonitor->VerifyFound(); |
| |
| // mode must be a valid VkCopyAccelerationStructureModeKHR value |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-mode-parameter"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR); |
| m_errorMonitor->VerifyFound(); |
| |
| // This command must only be called outside of a render pass instance |
| InitRenderTarget(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-renderpass"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_command_buffer.EndRenderPass(); |
| m_errorMonitor->VerifyFound(); |
| |
| vkt::DeviceMemory host_memory; |
| host_memory.Init(*m_device, |
| vkt::DeviceMemory::GetResourceAllocInfo(*m_device, dst_as_without_mem.MemoryRequirements().memoryRequirements, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)); |
| |
| VkBindAccelerationStructureMemoryInfoNV bind_info = vku::InitStructHelper(); |
| bind_info.accelerationStructure = dst_as_without_mem; |
| bind_info.memory = host_memory; |
| vk::BindAccelerationStructureMemoryNV(*m_device, 1, &bind_info); |
| |
| uint64_t handle; |
| vk::GetAccelerationStructureHandleNV(*m_device, dst_as_without_mem, sizeof(uint64_t), &handle); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-buffer-03719"); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, dst_as_without_mem, src_as, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdCopyAccelerationStructureNV-buffer-03718"); |
| const vkt::Buffer bot_level_as_scratch2 = dst_as_without_mem.CreateScratchBuffer(*m_device); |
| vk::CmdBuildAccelerationStructureNV(m_command_buffer, &bot_level_as_create_info.info, VK_NULL_HANDLE, 0, VK_FALSE, |
| dst_as_without_mem, VK_NULL_HANDLE, bot_level_as_scratch, 0); |
| vk::CmdCopyAccelerationStructureNV(m_command_buffer, src_as, dst_as_without_mem, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeRayTracingNV, DescriptorBuffers) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(descriptor_buffer_properties); |
| |
| VkDeviceAddress invalid_buffer = CastToHandle<VkDeviceAddress, uintptr_t>(0xbaadbeef); |
| |
| uint8_t buffer[128]; |
| VkDescriptorAddressInfoEXT dai = vku::InitStructHelper(); |
| dai.address = invalid_buffer; |
| dai.range = 64; |
| dai.format = VK_FORMAT_R8_UINT; |
| |
| VkDescriptorGetInfoEXT dgi = vku::InitStructHelper(); |
| dgi.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; |
| dgi.data.pStorageTexelBuffer = &dai; |
| m_errorMonitor->SetDesiredError("VUID-VkDescriptorGetInfoEXT-type-08029"); |
| vk::GetDescriptorEXT(device(), &dgi, descriptor_buffer_properties.storageBufferDescriptorSize, &buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeRayTracingNV, DescriptorGetInfo) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| RETURN_IF_SKIP(NvInitFrameworkForRayTracingTest()); |
| RETURN_IF_SKIP(InitState()); |
| |
| uint8_t buffer[128]; |
| VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(descriptor_buffer_properties); |
| |
| VkDescriptorGetInfoEXT dgi = vku::InitStructHelper(); |
| dgi.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; |
| dgi.data.accelerationStructure = 0; |
| m_errorMonitor->SetDesiredError("VUID-VkDescriptorDataEXT-type-08042"); |
| vk::GetDescriptorEXT(device(), &dgi, descriptor_buffer_properties.accelerationStructureDescriptorSize, &buffer); |
| m_errorMonitor->VerifyFound(); |
| } |