| /* |
| * Copyright (c) 2020-2026 The Khronos Group Inc. |
| * Copyright (c) 2020-2026 Valve Corporation |
| * Copyright (c) 2020-2026 LunarG, Inc. |
| * Copyright (c) 2020-2022 Google, Inc. |
| * |
| * 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 <cmath> |
| #include <vulkan/utility/vk_format_utils.h> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/descriptor_helper.h" |
| #include "../framework/ray_tracing_objects.h" |
| #include "../framework/gpu_av_helper.h" |
| #include "utils/math_utils.h" |
| |
| class NegativeGpuAVRayTracing : public GpuAVRayTracingTest {}; |
| |
| // In practice, tracing more rays than the driver allows will likely crash it |
| // so disable this test |
| TEST_F(NegativeGpuAVRayTracing, DISABLED_CmdTraceRaysIndirect) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| VkPhysicalDeviceRayTracingPipelinePropertiesKHR rt_pipeline_props = vku::InitStructHelper(); |
| VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&rt_pipeline_props); |
| vk::GetPhysicalDeviceProperties2(Gpu(), &props2); |
| |
| if (rt_pipeline_props.maxRayDispatchInvocationCount == vvl::kU32Max) { |
| GTEST_SKIP() << "maxRayDispatchInvocationCount is maxed out, cannot go past it, skipping test"; |
| } |
| |
| // Create and fill buffers storing indirect data (ray query dimensions) |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| vkt::Buffer trace_rays_big_width(*m_device, 4096, buffer_usage, vkt::device_address); |
| |
| VkTraceRaysIndirectCommandKHR trace_rays_dim{rt_pipeline_props.maxRayDispatchInvocationCount + 1, 1, 1}; |
| |
| uint8_t* ray_query_dimensions_buffer_1_ptr = (uint8_t*)trace_rays_big_width.Memory().Map(); |
| std::memcpy(ray_query_dimensions_buffer_1_ptr, &trace_rays_dim, sizeof(trace_rays_dim)); |
| |
| trace_rays_dim = {1, rt_pipeline_props.maxRayDispatchInvocationCount + 1, 1}; |
| |
| vkt::Buffer trace_rays_big_height(*m_device, 4096, buffer_usage, vkt::device_address); |
| |
| uint8_t* ray_query_dimensions_buffer_2_ptr = (uint8_t*)trace_rays_big_height.Memory().Map(); |
| std::memcpy(ray_query_dimensions_buffer_2_ptr, &trace_rays_dim, sizeof(trace_rays_dim)); |
| |
| trace_rays_dim = {1, 1, rt_pipeline_props.maxRayDispatchInvocationCount + 1}; |
| |
| vkt::Buffer trace_ray_big_depth(*m_device, 4096, buffer_usage, vkt::device_address); |
| |
| uint8_t* ray_query_dimensions_buffer_3_ptr = (uint8_t*)trace_ray_big_depth.Memory().Map(); |
| std::memcpy(ray_query_dimensions_buffer_3_ptr, &trace_rays_dim, sizeof(trace_rays_dim)); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| |
| if (uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupCount[0]) * |
| uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupSize[0]) < |
| uint64_t(rt_pipeline_props.maxRayDispatchInvocationCount + 1)) { |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-width-03638"); |
| } |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-width-03641"); |
| vk::CmdTraceRaysIndirectKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, trace_rays_big_width.Address()); |
| |
| if (uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupCount[1]) * |
| uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupSize[1]) < |
| uint64_t(rt_pipeline_props.maxRayDispatchInvocationCount + 1)) { |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-height-03639"); |
| } |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-width-03641"); |
| vk::CmdTraceRaysIndirectKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, trace_rays_big_height.Address()); |
| |
| if (uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupCount[2]) * |
| uint64_t(PhysicalDeviceProps().limits.maxComputeWorkGroupSize[2]) < |
| uint64_t(rt_pipeline_props.maxRayDispatchInvocationCount + 1)) { |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-depth-03640"); |
| } |
| m_errorMonitor->SetDesiredError("VUID-VkTraceRaysIndirectCommandKHR-width-03641"); |
| vk::CmdTraceRaysIndirectKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, trace_ray_big_depth.Address()); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8545 |
| TEST_F(NegativeGpuAVRayTracing, DISABLED_BasicTraceRaysDeferredBuild) { |
| TEST_DESCRIPTION( |
| "Setup a ray tracing pipeline (ray generation, miss and closest hit shaders, and deferred build) and acceleration " |
| "structure, and trace one " |
| "ray. Only call traceRay in the ray generation shader"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| // Set shaders |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require // Requires SPIR-V 1.5 (Vulkan 1.2) |
| #extension GL_EXT_buffer_reference : enable |
| |
| layout(buffer_reference, std430) readonly buffer RayTracingParams { |
| vec4 nothing; |
| float Tmin; |
| float Tmax; |
| }; |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform uniform_buffer { |
| RayTracingParams rt_params; |
| }; |
| |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), rt_params.Tmin, vec3(0,0,1), rt_params.Tmax, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| const char* miss = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| |
| void main() { |
| hit = vec3(0.1, 0.2, 0.3); |
| } |
| )glsl"; |
| pipeline.AddGlslMissShader(miss); |
| |
| const char* closest_hit = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(location = 0) rayPayloadInEXT vec3 hit; |
| hitAttributeEXT vec2 baryCoord; |
| |
| void main() { |
| const vec3 barycentricCoords = vec3(1.0f - baryCoord.x - baryCoord.y, baryCoord.x, baryCoord.y); |
| hit = barycentricCoords; |
| } |
| )glsl"; |
| pipeline.AddGlslClosestHitShader(closest_hit); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| // Create TLAS |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| // Create uniform_buffer |
| vkt::Buffer rt_params_buffer(*m_device, 4 * sizeof(float), 0, vkt::device_address); // missing space for Tmin and Tmax |
| vkt::Buffer uniform_buffer(*m_device, 16, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| auto data = static_cast<VkDeviceAddress*>(uniform_buffer.Memory().Map()); |
| data[0] = rt_params_buffer.Address(); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, 16, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| // Add one to use the descriptor slot GPU-AV tried to reserve |
| const uint32_t max_bound_desc_sets = m_device->Physical().limits_.maxBoundDescriptorSets + 1; |
| |
| // First try to use too many sets in the pipeline layout |
| { |
| m_errorMonitor->SetDesiredWarning( |
| "This Pipeline Layout has too many descriptor sets that will not allow GPU shader instrumentation to be setup for " |
| "pipelines created with it"); |
| std::vector<const vkt::DescriptorSetLayout*> desc_set_layouts(max_bound_desc_sets); |
| for (uint32_t i = 0; i < max_bound_desc_sets; i++) { |
| desc_set_layouts[i] = &pipeline.GetDescriptorSet().layout_; |
| } |
| vkt::PipelineLayout bad_pipe_layout(*m_device, desc_set_layouts); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Then use the maximum allowed number of sets |
| std::vector<const vkt::DescriptorSetLayout*> des_set_layouts(max_bound_desc_sets - 1); |
| for (uint32_t i = 0; i < max_bound_desc_sets - 1; i++) { |
| des_set_layouts[i] = &pipeline.GetDescriptorSet().layout_; |
| } |
| VkPipelineLayoutCreateInfo pipe_layout_ci = vku::InitStructHelper(); |
| |
| pipeline.GetPipelineLayout().Init(*m_device, pipe_layout_ci, des_set_layouts); |
| |
| // Deferred pipeline build |
| RETURN_IF_SKIP(pipeline.DeferBuild()); |
| RETURN_IF_SKIP(pipeline.Build()); |
| |
| // Bind descriptor set, pipeline, and trace rays |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferRayGenShader) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in a ray " |
| "generation shader"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2); |
| AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR cubes_tlas = |
| vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = { ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0) }; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,-1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &cubes_tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| vkt::Buffer sbt_buffer_ray_gen_1 = pipeline.GetTraceRaysSbtIndirectBuffer(0, 1, 1, 1); |
| vk::CmdTraceRaysIndirect2KHR(m_command_buffer, sbt_buffer_ray_gen_1.Address()); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| |
| { |
| uniform_buffer_ptr[0] = 25; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 1); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-None-10068", 1); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("08114", 3); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferMissShader) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in a " |
| "miss shader"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR cubes_tlas = |
| vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,-1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| payload.payload = ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &cubes_tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| |
| { |
| uniform_buffer_ptr[0] = 25; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 1); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferClosetHitShader) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in a " |
| "closest hit shader"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::accelerationStructureIndirectBuild); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| payload.payload = ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| |
| { |
| uniform_buffer_ptr[0] = 25; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 1); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferTwoClosetHitShader) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in two " |
| "different closest hit shaders"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| payload.payload += ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| const uint32_t miss_shader_i = 1; |
| |
| // Supposed to hit cube 2, and invoke closestHitShader2 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, miss_shader_i, ray, payload); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader2(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = 999 * barycentric_coords; |
| payload.payload += ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader2"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| |
| { |
| uniform_buffer_ptr[0] = 25; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 2); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 3); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferRayGenShaderGPL) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in a ray " |
| "generation shader coming from a graphics pipeline library"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| AddRequiredFeature(vkt::Feature::pipelineLibraryGroupHandles); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR cubes_tlas = |
| vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| [[vk::binding(10, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| ray_payload.payload = ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,-1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload ray_payload) |
| { |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload ray_payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline_lib(*this, m_device); |
| pipeline_lib.InitLibraryInfo(16 * sizeof(float), false); |
| pipeline_lib.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 10); |
| pipeline_lib.CreateDescriptorIndexingSet(); |
| |
| pipeline_lib.BuildPipeline(); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.InitLibraryInfo(16 * sizeof(float), true); |
| pipeline.AddLibrary(pipeline_lib); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 10); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &cubes_tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| vkt::Buffer debug_buffer(*m_device, 16 * sizeof(uint32_t), |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, kHostVisibleMemProps); |
| uint32_t* debug_buffer_ptr = (uint32_t*)debug_buffer.Memory().Map(); |
| memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(10, debug_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| vkt::Buffer sbt_buffer_ray_gen_1 = pipeline.GetTraceRaysSbtIndirectBuffer(0, 1, 1, 1); |
| vk::CmdTraceRaysIndirect2KHR(m_command_buffer, sbt_buffer_ray_gen_1.Address()); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| { |
| uniform_buffer_ptr[0] = 42; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 1); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-None-10068", 1); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("08114", 3); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| ASSERT_EQ(debug_buffer_ptr[0], 4); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferMissShaderGPL) { |
| TEST_DESCRIPTION( |
| "GPU validation: Verify detection of out-of-bounds descriptor array indexing and use of uninitialized descriptors in a " |
| "miss shader coming from a graphics pipeline library"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect); |
| AddRequiredFeature(vkt::Feature::rayTracingPipelineTraceRaysIndirect2); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| AddRequiredFeature(vkt::Feature::runtimeDescriptorArray); |
| AddRequiredFeature(vkt::Feature::descriptorBindingSampledImageUpdateAfterBind); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| AddRequiredFeature(vkt::Feature::descriptorBindingVariableDescriptorCount); |
| AddRequiredFeature(vkt::Feature::shaderSampledImageArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::shaderStorageBufferArrayNonUniformIndexing); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| AddRequiredFeature(vkt::Feature::pipelineLibraryGroupHandles); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas; |
| vkt::as::BuildGeometryInfoKHR cubes_tlas = |
| vkt::as::blueprint::GetCubesTLAS(*m_device, m_command_buffer, *m_default_queue, cube_blas); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| struct UniformBuffer { |
| uint ray_payload_i; |
| }; |
| [[vk::binding(1, 0)]] ConstantBuffer<UniformBuffer> uniform_buffer; |
| |
| [[vk::binding(2, 0)]] uniform RWStructuredBuffer<uint4> ray_payload_buffer[]; |
| |
| [[vk::binding(10, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,-1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload ray_payload) |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| ray_payload.payload = ray_payload_buffer[uniform_buffer.ray_payload_i].Load(0); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload ray_payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline_lib(*this, m_device); |
| pipeline_lib.InitLibraryInfo(16 * sizeof(float), false); |
| pipeline_lib.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline_lib.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 10); |
| pipeline_lib.CreateDescriptorIndexingSet(); |
| |
| pipeline_lib.BuildPipeline(); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.InitLibraryInfo(16 * sizeof(float), true); |
| pipeline.AddLibrary(pipeline_lib); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| // Make a uniform buffer to be passed to the shader that contains the invalid array index. |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| |
| // Make another buffer to populate the buffer array to be indexed |
| vkt::Buffer ray_payload_buffer(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, 6); |
| pipeline.AddDescriptorIndexingBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 10); |
| pipeline.CreateDescriptorIndexingSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorAccelStruct(0, 1, &cubes_tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| // Intentionally not writing to 6th array element |
| for (uint32_t i = 0; i < 5; ++i) { |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(2, ray_payload_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); |
| } |
| vkt::Buffer debug_buffer(*m_device, 16 * sizeof(uint32_t), |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, kHostVisibleMemProps); |
| uint32_t* debug_buffer_ptr = (uint32_t*)debug_buffer.Memory().Map(); |
| memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| pipeline.GetDescriptorIndexingSet().WriteDescriptorBufferInfo(10, debug_buffer, 0, VK_WHOLE_SIZE, |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| pipeline.GetDescriptorIndexingSet().UpdateDescriptorSets(); |
| |
| { |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorIndexingSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| // Invoke ray gen shader 1 |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| vkt::Buffer sbt_buffer_ray_gen_1 = pipeline.GetTraceRaysSbtIndirectBuffer(0, 1, 1, 1); |
| vk::CmdTraceRaysIndirect2KHR(m_command_buffer, sbt_buffer_ray_gen_1.Address()); |
| |
| m_command_buffer.End(); |
| |
| uint32_t* uniform_buffer_ptr = (uint32_t*)uniform_buffer.Memory().Map(); |
| { |
| uniform_buffer_ptr[0] = 42; |
| SCOPED_TRACE("Out of Bounds"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-10068", 1); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysIndirect2KHR-None-10068", 1); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| uniform_buffer_ptr[0] = 5; |
| SCOPED_TRACE("uninitialized"); |
| m_errorMonitor->SetDesiredError("08114", 3); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| ASSERT_EQ(debug_buffer_ptr[0], 4); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidBlasReference1) { |
| TEST_DESCRIPTION( |
| "Validate an invalid BLAS reference in a TLAS build - first element BLAS ref invalid, subsequent ones valid." |
| "Trace a ray into the built TLAS to confirm it was built correctly without the invalid ref but with the valid ones."); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| cube_instances[0].UpdateAccelerationStructureInstance(0, [](VkAccelerationStructureInstanceKHR& instance) { |
| instance.accelerationStructureReference = static_cast<uint64_t>(0xbaadbeef); |
| }); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03717", |
| "Infos\\[0\\].pGeometries\\[0\\].geometry.instances<VkAccelerationStructureInstance>" |
| "\\[0\\].accelerationStructureReference \\(0xbaadbeef\\)"); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built |
| ASSERT_EQ(debug_buffer_ptr[0], 1); |
| ASSERT_EQ(debug_buffer_ptr[1], 0); |
| ASSERT_EQ(debug_buffer_ptr[2], 1); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidBlasReference2) { |
| TEST_DESCRIPTION( |
| "Validate an invalid BLAS reference in a TLAS build - first element BLAS ref invalid, subsequent ones valid." |
| "Trace a ray into the built TLAS to confirm it was built correctly without the invalid ref but with the valid ones." |
| "Add other BLAS builds to the build command, and assert they were also done."); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> tlas_1(1); |
| tlas_1[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| tlas_1[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| tlas_1[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| tlas_1[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| tlas_1[0].UpdateAccelerationStructureInstance(0, [](VkAccelerationStructureInstanceKHR& instance) { |
| instance.accelerationStructureReference = static_cast<uint64_t>(0x10); |
| }); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_and_blass_build_info_1; |
| { |
| vkt::as::GeometryKHR cube_1(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas_1 = |
| vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| tlas_and_blass_build_info_1.emplace_back(std::move(cube_blas_1)); |
| |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(tlas_1)); |
| tlas_and_blass_build_info_1.emplace_back(std::move(tlas)); |
| |
| vkt::as::GeometryKHR cube_2(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas_2 = |
| vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| tlas_and_blass_build_info_1.emplace_back(std::move(cube_blas_2)); |
| |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_and_blass_build_info_1); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12281", |
| "Infos\\[1\\].pGeometries\\[0\\].geometry.instances<VkAccelerationStructureInstance>" |
| "\\[0\\].accelerationStructureReference \\(0x10\\)"); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Build a 2nd TLAS referencing the 2 BLAS built along with the first TLAS. |
| // Rays will be traced into this TLAS, to make sure those BLAS were correctly built. |
| std::vector<vkt::as::GeometryKHR> tlas_2(1); |
| tlas_2[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| tlas_2[0].AddInstanceDeviceAccelStructRef(*m_device, tlas_and_blass_build_info_1[0].GetDstAS()->handle(), cube_instance_1); |
| tlas_2[0].AddInstanceDeviceAccelStructRef(*m_device, tlas_and_blass_build_info_1[2].GetDstAS()->handle(), cube_instance_2); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info_2; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(tlas_2)); |
| tlas_build_info_2.emplace_back(std::move(tlas)); |
| |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info_2); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| } |
| |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| |
| // Will hit cube 2 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(0,0,1); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_and_blass_build_info_1[1].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built |
| ASSERT_EQ(debug_buffer_ptr[0], 1); |
| ASSERT_EQ(debug_buffer_ptr[1], 0); |
| ASSERT_EQ(debug_buffer_ptr[2], 2); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info_2[0].GetDstAS()->handle()); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built |
| ASSERT_EQ(debug_buffer_ptr[0], 2); |
| ASSERT_EQ(debug_buffer_ptr[1], 0); |
| ASSERT_EQ(debug_buffer_ptr[2], 4); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidBlasReference3) { |
| TEST_DESCRIPTION( |
| "Validate an invalid BLAS reference in a TLAS build - first element BLAS ref invalid because its underlying buffer has " |
| "been destroyed, subsequent ones valid." |
| "Trace a ray into the built TLAS to confirm it was built correctly without the invalid ref but with the valid ones."); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| const VkDeviceAddress cube_blas_addr = cube_blas.GetDstAS()->GetAccelerationStructureDeviceAddress(); |
| // Destroy buffer, but BLAS will be referenced in a TLAS build command |
| cube_blas.GetDstAS()->GetBuffer().Destroy(); |
| |
| std::ostringstream expected_error_1; |
| expected_error_1 << "Infos\\[0\\].pGeometries\\[0\\].geometry.instances<VkAccelerationStructureInstance>\\[0\\]." |
| "accelerationStructureReference \\(0x" |
| << std::hex << cube_blas_addr << "\\).*underlying buffer.*VkAccelerationStructureKHR.*" |
| << CastFromHandle<uint64_t>(cube_blas.GetDstAS()->handle()); |
| std::ostringstream expected_error_2; |
| expected_error_2 << "Infos\\[0\\].pGeometries\\[0\\].geometry.instances<VkAccelerationStructureInstance>\\[1\\]." |
| "accelerationStructureReference \\(0x" |
| << std::hex << cube_blas_addr << "\\).*underlying buffer.*VkAccelerationStructureKHR.*" |
| << CastFromHandle<uint64_t>(cube_blas.GetDstAS()->handle()); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12281", expected_error_1.str()); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-12281", expected_error_2.str()); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly *not* built |
| ASSERT_EQ(debug_buffer_ptr[0], 1); |
| ASSERT_EQ(debug_buffer_ptr[1], 1); |
| ASSERT_EQ(debug_buffer_ptr[2], 0); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidBlasReference4) { |
| TEST_DESCRIPTION( |
| "Validate an invalid BLAS reference in a TLAS build - BLAS buffer memory is destroyed prior to build, this is invalid." |
| "Trace a ray into the built TLAS to confirm it was built correctly (and is empty, so no intersection with it should be " |
| "found)."); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| cube_blas.GetDstAS()->GetBuffer().Memory().Destroy(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03709", 3); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built |
| ASSERT_EQ(debug_buffer_ptr[0], 1); |
| ASSERT_EQ(debug_buffer_ptr[1], 1); |
| ASSERT_EQ(debug_buffer_ptr[2], 0); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, BLASBuiltAndUsedInTLAS) { |
| TEST_DESCRIPTION("In the same vkCmdBuildAccelerationStructures, build a BLAS and also use it in a TLAS build"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| |
| // Create a blas, backed by a buffer also used to back a blas referenced in the previous TLAS. |
| // => Their memory overlaps, building them in the same command is invalid. |
| vkt::as::GeometryKHR cube_1(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas_1 = |
| vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| const VkAccelerationStructureBuildSizesInfoKHR cube_blas_size_info = cube_blas_1.GetSizeInfo(); |
| |
| VkBufferCreateInfo cube_blas_1_buffer_ci = vku::InitStructHelper(); |
| cube_blas_1_buffer_ci.size = cube_blas_size_info.accelerationStructureSize; |
| cube_blas_1_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | |
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer cube_blas_1_buffer; |
| cube_blas_1_buffer.InitNoMemory(*m_device, cube_blas_1_buffer_ci); |
| cube_blas_1_buffer.BindMemory(cube_blas.GetDstAS()->GetBuffer().Memory(), 0); |
| |
| cube_blas_1.GetDstAS()->SetDeviceBuffer(std::move(cube_blas_1_buffer)); |
| tlas_build_info.emplace_back(std::move(cube_blas_1)); |
| |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03706", 2); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built, but is empty |
| ASSERT_EQ(debug_buffer_ptr[0], 1); // Ray gen shader invocations count |
| ASSERT_EQ(debug_buffer_ptr[1], 1); // Miss shader invocations count |
| ASSERT_EQ(debug_buffer_ptr[2], 0); // Closest hit shader invocations count |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, BLASUpdatedAndUsedInTLAS) { |
| TEST_DESCRIPTION("In the same vkCmdBuildAccelerationStructures, update a BLAS and also use it in a TLAS build"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| |
| // Update cube_blas while it is also referenced in TLAS build |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| tlas_build_info.emplace_back(std::move(cube_blas)); |
| |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBuildAccelerationStructuresKHR-dstAccelerationStructure-03706", 2); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built, but is empty |
| ASSERT_EQ(debug_buffer_ptr[0], 1); // Ray gen shader invocations count |
| ASSERT_EQ(debug_buffer_ptr[1], 1); // Miss shader invocations count |
| ASSERT_EQ(debug_buffer_ptr[2], 0); // Closest hit shader invocations count |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, TLASinBLASlist) { |
| TEST_DESCRIPTION("Setup a RT pipeline, create a TLAS that contains a reference to another TLAS"); |
| |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| std::vector<vkt::as::GeometryKHR> cube_instances(1); |
| cube_instances[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_1{}; |
| cube_instance_1.transform.matrix[0][0] = 1.0f; |
| cube_instance_1.transform.matrix[1][1] = 1.0f; |
| cube_instance_1.transform.matrix[2][2] = 1.0f; |
| cube_instance_1.transform.matrix[0][3] = 50.0f; |
| cube_instance_1.transform.matrix[1][3] = 0.0f; |
| cube_instance_1.transform.matrix[2][3] = 0.0f; |
| cube_instance_1.mask = 0xff; |
| cube_instance_1.instanceCustomIndex = 0; |
| // Cube instance 1 will be associated to closest hit shader 1 |
| cube_instance_1.instanceShaderBindingTableRecordOffset = 0; |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| VkAccelerationStructureInstanceKHR cube_instance_2{}; |
| cube_instance_2.transform.matrix[0][0] = 1.0f; |
| cube_instance_2.transform.matrix[1][1] = 1.0f; |
| cube_instance_2.transform.matrix[2][2] = 1.0f; |
| cube_instance_2.transform.matrix[0][3] = 0.0f; |
| cube_instance_2.transform.matrix[1][3] = 0.0f; |
| cube_instance_2.transform.matrix[2][3] = 50.0f; |
| cube_instance_2.mask = 0xff; |
| cube_instance_2.instanceCustomIndex = 0; |
| // Cube instance 2 will be associated to closest hit shader 1 |
| cube_instance_2.instanceShaderBindingTableRecordOffset = 0; |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_2); |
| |
| // Create a TLAS, and add a reference to it in the cubes_instances BLAS list |
| // This list being used to create a TLAS, this is invalid |
| std::vector<vkt::as::GeometryKHR> cube_instances_2(1); |
| cube_instances_2[0].SetType(vkt::as::GeometryKHR::Type::Instance); |
| cube_instances_2[0].AddInstanceDeviceAccelStructRef(*m_device, cube_blas.GetDstAS()->handle(), cube_instance_1); |
| |
| vkt::as::BuildGeometryInfoKHR unwanted_tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances_2)); |
| m_command_buffer.Begin(); |
| unwanted_tlas.BuildCmdBuffer(m_command_buffer); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| |
| cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, unwanted_tlas.GetDstAS()->handle(), cube_instance_1); |
| |
| std::vector<vkt::as::BuildGeometryInfoKHR> tlas_build_info; |
| { |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::CreateTLAS(*m_device, std::move(cube_instances)); |
| tlas_build_info.emplace_back(std::move(tlas)); |
| m_command_buffer.Begin(); |
| vkt::as::BuildAccelerationStructuresKHR(m_command_buffer, tlas_build_info); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_errorMonitor->SetDesiredError("UID-vkCmdBuildAccelerationStructuresKHR-pInfos-12281"); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Past this point, goal is to make sure using `tlas` is safe, and the TLAS reference found in its BLAS reference list |
| // has just been removed and is not causing a crash. |
| |
| // Buffer used to count invocations for the 3 shaders |
| vkt::Buffer debug_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| std::memset(debug_buffer_ptr, 0, (size_t)debug_buffer.CreateInfo().size); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| [[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer; |
| |
| struct RayPayload { |
| uint4 payload; |
| float3 hit; |
| }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| InterlockedAdd(debug_buffer[0], 1); |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.TMin = 0.01; |
| ray.TMax = 1000.0; |
| |
| // Will hit cube 1 |
| ray.Origin = float3(0,0,0); |
| ray.Direction = float3(1,0,0); |
| TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) |
| { |
| InterlockedAdd(debug_buffer[1], 1); |
| payload.hit = float3(0.1, 0.2, 0.3); |
| } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) |
| { |
| InterlockedAdd(debug_buffer[2], 1); |
| const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, |
| attr.barycentrics.y); |
| payload.hit = barycentric_coords; |
| } |
| )slang"; |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| pipeline.Build(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas_build_info[0].GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| |
| vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0); |
| vk::CmdTraceRaysKHR(m_command_buffer, &sbt_ray_gen_1.ray_gen_sbt, &sbt_ray_gen_1.miss_sbt, &sbt_ray_gen_1.hit_sbt, |
| &sbt_ray_gen_1.callable_sbt, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Make sure expected ray tracing setup worked, indicating the TLAS was correctly built |
| ASSERT_EQ(debug_buffer_ptr[0], 1); |
| ASSERT_EQ(debug_buffer_ptr[1], 0); |
| ASSERT_EQ(debug_buffer_ptr[2], 1); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OutOfBoundsIndex) { |
| TEST_DESCRIPTION("In the geometry specifying a cube and used to create an AS, have an out of bounds index."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| vkt::Buffer& cube_index_buffer = cube.GetTrianglesDeviceIndexBuffer(); |
| auto index_buffer_ptr = static_cast<uint32_t*>(cube_index_buffer.Memory().Map()); |
| index_buffer_ptr[0] = 30; |
| index_buffer_ptr[6] = 42; |
| index_buffer_ptr[35] = 666; |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAccelerationStructureBuildRangeInfoKHR-maxVertex-10774", |
| "Index \\(42\\) \\+ firstVertex \\(0\\) = 42"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAccelerationStructureBuildRangeInfoKHR-maxVertex-10774", |
| "Index \\(30\\) \\+ firstVertex \\(0\\) = 30"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAccelerationStructureBuildRangeInfoKHR-maxVertex-10774", |
| "Index \\(666\\) \\+ firstVertex \\(0\\) = 666"); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OutOfBoundsIndex2) { |
| TEST_DESCRIPTION( |
| "In the geometry specifying a cube and used to create an AS, have an out of bounds index. Set maxVertex to something other " |
| "than 7"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| cube.GetVkObj().geometry.triangles.maxVertex = 6; |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAccelerationStructureBuildRangeInfoKHR-maxVertex-10774", |
| "Index \\(7\\) \\+ firstVertex \\(0\\) = 7", 4); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OutOfBoundsIndex3) { |
| TEST_DESCRIPTION( |
| "In the geometry specifying a cube and used to create an AS, have an out of bounds index. Play with primitiveOffset"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| std::array<uint32_t, 3 * 2 * 6 * 2> indices = { |
| {// In bounds indices |
| 3, 0, 4, 4, 7, 3, 0, 4, 5, 0, 5, 1, 4, 5, 6, 4, 6, 7, 1, 6, 5, 1, 2, 6, 2, 6, 7, 2, 7, 3, 0, 1, 3, 1, 3, 2, |
| // Out of bounds |
| 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 0 + 0, 4 + 0, 5 + 0, 0 + 0, 5 + 0, 1 + 0, 4 + 0, 5 + 0, 6 + 0, 4 + 0, 6 + 0, |
| 7 + 0, 1 + 0, 6 + 0, 5 + 0, 1 + 0, 2 + 0, 6 + 0, 2 + 0, 6 + 0, 7 + 0, 2 + 0, 7 + 0, 3 + 0, 0 + 0, 1 + 0, 3 + 0, 1 + 0, |
| 3 + 0, 2 + 8}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer index_buffer(*m_device, sizeof(indices[0]) * indices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto index_buffer_ptr = static_cast<uint32_t*>(index_buffer.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_ptr); |
| index_buffer.Memory().Unmap(); |
| |
| cube.SetTrianglesDeviceIndexBuffer(std::move(index_buffer)); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| |
| cube_blas.GetBuildRanges()[0].primitiveOffset = 36 * sizeof(uint32_t); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAccelerationStructureBuildRangeInfoKHR-maxVertex-10774", |
| "Index \\(10\\) \\+ firstVertex \\(0\\) = 10", 1); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, IllFormedAabb) { |
| TEST_DESCRIPTION("Ill formed Aabb, where minima are superior to maxima"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayQuery); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| m_command_buffer.Begin(); |
| // Build Bottom Level Acceleration Structure |
| auto geometry = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device); |
| VkAabbPositionsKHR good_aabb; |
| good_aabb.minX = -1.0f; |
| good_aabb.maxX = 1.0f; |
| good_aabb.minY = -1.0f; |
| good_aabb.maxY = 1.0f; |
| good_aabb.minZ = -1.0f; |
| good_aabb.maxZ = 1.0f; |
| VkAabbPositionsKHR bad_aabb = good_aabb; |
| bad_aabb.minX = 2.0f; |
| bad_aabb.minY = 4.0f; |
| bad_aabb.minZ = 12345678.9123f; |
| std::array<VkAabbPositionsKHR, 4> aabbs = {{good_aabb, bad_aabb, good_aabb, bad_aabb}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer aabbs_buffer(*m_device, sizeof(aabbs[0]) * aabbs.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto aabbs_buffer_ptr = static_cast<VkAabbPositionsKHR*>(aabbs_buffer.Memory().Map()); |
| std::copy(aabbs.begin(), aabbs.end(), aabbs_buffer_ptr); |
| aabbs_buffer.Memory().Unmap(); |
| |
| geometry.SetAABBsDeviceBuffer(std::move(aabbs_buffer)); |
| geometry.SetPrimitiveCount(4); |
| |
| vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geometry)); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minX-03546", "primitive index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minY-03547", "primitive index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minZ-03548", "primitive index 1"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minX-03546", "primitive index 3"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minY-03547", "primitive index 3"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-VkAabbPositionsKHR-minZ-03548", "primitive index 3"); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, BuildAccelerationStructuresList2) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| m_command_buffer.Begin(); |
| auto geometry = vkt::as::blueprint::GeometrySimpleOnDeviceIndexedTriangleInfo(*m_device); |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer transform_buffer(*m_device, sizeof(VkTransformMatrixKHR), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| // clang-format off |
| VkTransformMatrixKHR transform_matrix = {{ |
| { 1.0f, 0.0f, 0.0f, 0.0f }, |
| { 0.0f, 1.0f, 1.0f, 0.0f }, |
| { 0.0f, 0.0f, 0.0f, 0.0f }, |
| }}; |
| // clang-format on |
| |
| auto transform_buffer_ptr = static_cast<VkTransformMatrixKHR*>(transform_buffer.Memory().Map()); |
| std::memcpy(transform_buffer_ptr + 64, &transform_matrix, sizeof(transform_matrix)); |
| transform_buffer.Memory().Unmap(); |
| |
| geometry.SetTrianglesTransformBuffer(std::move(transform_buffer)); |
| |
| vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geometry)); |
| blas.GetBuildRanges()[0].transformOffset = 64; |
| |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkTransformMatrixKHR-matrix-03799"); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidIndexBufferUpdate) { |
| TEST_DESCRIPTION("Use an updated index buffer in an AS build update."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| std::array<uint32_t, 3 * 2 * 6> indices = { |
| {3, 0, 4, 4, 7, 3, 0, 4, 5, 0, 5, 1, 4, 5, 6, 4, 6, 7, 1, 6, 5, 1, 2, 6, 2, 6, 7, 2, 7, 3, 0, 1, 3, 1, 3, 2}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer index_buffer(*m_device, sizeof(indices[0]) * indices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto index_buffer_ptr = static_cast<uint32_t*>(index_buffer.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_ptr); |
| index_buffer.Memory().Unmap(); |
| |
| cube.SetTrianglesDeviceIndexBuffer(std::move(index_buffer)); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| SCOPED_TRACE("Update index buffer values"); |
| index_buffer_ptr = static_cast<uint32_t*>(cube_blas.GetGeometries()[0].GetTrianglesDeviceIndexBuffer().Memory().Map()); |
| |
| index_buffer_ptr[0] = 0; |
| index_buffer_ptr[5] = 2; |
| index_buffer_ptr[indices.size() - 1] = 1; |
| |
| cube_blas.GetGeometries()[0].GetTrianglesDeviceIndexBuffer().Memory().Unmap(); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 0.*was 3, but.*is 0"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| SCOPED_TRACE("Change index buffer, use it an offset through using primitiveOffset, and also update index values"); |
| constexpr uint32_t index_buffer_2_byte_offset = 64; |
| constexpr uint32_t index_buffer_2_dword_offset = index_buffer_2_byte_offset / sizeof(uint32_t); |
| vkt::Buffer index_buffer_2(*m_device, sizeof(indices[0]) * indices.size() + index_buffer_2_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_2_ptr = static_cast<uint32_t*>(index_buffer_2.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_2_ptr + index_buffer_2_dword_offset); |
| |
| index_buffer_2_ptr[0 + index_buffer_2_dword_offset] = 0; |
| index_buffer_2_ptr[5 + index_buffer_2_dword_offset] = 2; |
| index_buffer_2_ptr[indices.size() - 1 + index_buffer_2_dword_offset] = 1; |
| |
| index_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[0].SetTrianglesDeviceIndexBuffer(std::move(index_buffer_2)); |
| auto build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[0].primitiveOffset = index_buffer_2_byte_offset; |
| cube_blas.SetBuildRanges(build_range_infos); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 0.*was 3, but.*is 0"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[0].primitiveOffset = 0; |
| cube_blas.SetBuildRanges(build_range_infos); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidIndexBufferUpdate2) { |
| TEST_DESCRIPTION("Use an updated index buffer in an AS build update."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| constexpr std::array<uint32_t, 3 * 2 * 6> indices = { |
| {3, 0, 4, 4, 7, 3, 0, 4, 5, 0, 5, 1, 4, 5, 6, 4, 6, 7, 1, 6, 5, 1, 2, 6, 2, 6, 7, 2, 7, 3, 0, 1, 3, 1, 3, 2}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| auto get_cube = [&]() { |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| vkt::Buffer index_buffer(*m_device, sizeof(indices[0]) * indices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto index_buffer_ptr = static_cast<uint32_t*>(index_buffer.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_ptr); |
| index_buffer.Memory().Unmap(); |
| |
| cube.SetTrianglesDeviceIndexBuffer(std::move(index_buffer)); |
| |
| return cube; |
| }; |
| |
| vkt::as::GeometryKHR cube_0 = get_cube(); |
| vkt::as::GeometryKHR cube_1 = get_cube(); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = |
| vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube_0)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| cube_blas.GetGeometries().emplace_back(std::move(cube_1)); |
| cube_blas.SetBuildRanges(cube_blas.GetBuildRangeInfosFromGeometries()); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| SCOPED_TRACE("Update index buffer values"); |
| auto index_buffer_ptr = static_cast<uint32_t*>(cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Memory().Map()); |
| index_buffer_ptr[0] = 0; |
| index_buffer_ptr[5] = 2; |
| index_buffer_ptr[indices.size() - 1] = 1; |
| cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Memory().Unmap(); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 0.*was 3, but.*is 0"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| SCOPED_TRACE("Change index buffer, use it an offset through using primitiveOffset, and also update index values"); |
| constexpr uint32_t index_buffer_2_byte_offset = 64; |
| constexpr uint32_t index_buffer_2_dword_offset = index_buffer_2_byte_offset / sizeof(uint32_t); |
| vkt::Buffer index_buffer_2(*m_device, sizeof(indices[0]) * indices.size() + index_buffer_2_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_2_ptr = static_cast<uint32_t*>(index_buffer_2.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_2_ptr + index_buffer_2_dword_offset); |
| |
| index_buffer_2_ptr[0 + index_buffer_2_dword_offset] = 0; |
| index_buffer_2_ptr[5 + index_buffer_2_dword_offset] = 2; |
| index_buffer_2_ptr[indices.size() - 1 + index_buffer_2_dword_offset] = 1; |
| |
| index_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[1].SetTrianglesDeviceIndexBuffer(std::move(index_buffer_2)); |
| auto build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[1].primitiveOffset = index_buffer_2_byte_offset; |
| cube_blas.SetBuildRanges(build_range_infos); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 0.*was 3, but.*is 0"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[1].primitiveOffset = 0; |
| cube_blas.SetBuildRanges(build_range_infos); |
| } |
| |
| { |
| SCOPED_TRACE( |
| "Change index buffer, use it an offset through changing base index data address, and also update index values"); |
| constexpr uint32_t index_buffer_2_byte_offset = 64; |
| constexpr uint32_t index_buffer_2_dword_offset = index_buffer_2_byte_offset / sizeof(uint32_t); |
| vkt::Buffer index_buffer_2(*m_device, sizeof(indices[0]) * indices.size() + index_buffer_2_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_2_ptr = static_cast<uint32_t*>(index_buffer_2.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_2_ptr + index_buffer_2_dword_offset); |
| |
| index_buffer_2_ptr[0 + index_buffer_2_dword_offset] = 0; |
| index_buffer_2_ptr[5 + index_buffer_2_dword_offset] = 2; |
| index_buffer_2_ptr[indices.size() - 1 + index_buffer_2_dword_offset] = 1; |
| |
| index_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[1].SetTrianglesDeviceIndexBuffer(std::move(index_buffer_2)); |
| const VkDeviceAddress index_buffer_addr = cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Address(); |
| cube_blas.GetGeometries()[1].SetTrianglesIndexBufferDeviceAddress(index_buffer_addr + index_buffer_2_byte_offset); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 0.*was 3, but.*is 0"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, InvalidIndexBufferUpdate2Uint16) { |
| TEST_DESCRIPTION("Use an updated index buffer in an AS build update. Use uint16"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| constexpr std::array<uint16_t, 3 * 2 * 6> indices = { |
| {3, 0, 4, 4, 7, 3, 0, 4, 5, 0, 5, 1, 4, 5, 6, 4, 6, 7, 1, 6, 5, 1, 2, 6, 2, 6, 7, 2, 7, 3, 0, 1, 3, 1, 3, 2}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| auto get_cube = [&]() { |
| vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device)); |
| |
| vkt::Buffer index_buffer(*m_device, sizeof(indices[0]) * indices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto index_buffer_ptr = static_cast<uint16_t*>(index_buffer.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_ptr); |
| index_buffer.Memory().Unmap(); |
| |
| cube.SetTrianglesDeviceIndexBuffer(std::move(index_buffer), VK_INDEX_TYPE_UINT16); |
| |
| return cube; |
| }; |
| |
| vkt::as::GeometryKHR cube_0 = get_cube(); |
| vkt::as::GeometryKHR cube_1 = get_cube(); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = |
| vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube_0)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| cube_blas.GetGeometries().emplace_back(std::move(cube_1)); |
| cube_blas.SetBuildRanges(cube_blas.GetBuildRangeInfosFromGeometries()); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| SCOPED_TRACE("Update index buffer values"); |
| auto index_buffer_ptr = static_cast<uint16_t*>(cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Memory().Map()); |
| index_buffer_ptr[5] = 2; |
| index_buffer_ptr[indices.size() - 1] = 1; |
| cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Memory().Unmap(); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| SCOPED_TRACE("Change index buffer, use it an offset through using primitiveOffset, and also update index values"); |
| constexpr uint32_t index_buffer_2_byte_offset = 64; |
| constexpr uint32_t index_buffer_2_word_offset = index_buffer_2_byte_offset / sizeof(uint16_t); |
| vkt::Buffer index_buffer_2(*m_device, sizeof(indices[0]) * indices.size() + index_buffer_2_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_2_ptr = static_cast<uint16_t*>(index_buffer_2.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_2_ptr + index_buffer_2_word_offset); |
| |
| index_buffer_2_ptr[5 + index_buffer_2_word_offset] = 2; |
| index_buffer_2_ptr[indices.size() - 1 + index_buffer_2_word_offset] = 1; |
| |
| index_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[1].SetTrianglesDeviceIndexBuffer(std::move(index_buffer_2), VK_INDEX_TYPE_UINT16); |
| auto build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[1].primitiveOffset = index_buffer_2_byte_offset; |
| cube_blas.SetBuildRanges(build_range_infos); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| build_range_infos = cube_blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[1].primitiveOffset = 0; |
| cube_blas.SetBuildRanges(build_range_infos); |
| } |
| |
| { |
| SCOPED_TRACE( |
| "Change index buffer, use it an offset through changing base index data address, and also update index values"); |
| constexpr uint32_t index_buffer_2_byte_offset = 64; |
| constexpr uint32_t index_buffer_2_word_offset = index_buffer_2_byte_offset / sizeof(uint16_t); |
| vkt::Buffer index_buffer_2(*m_device, sizeof(indices[0]) * indices.size() + index_buffer_2_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_2_ptr = static_cast<uint16_t*>(index_buffer_2.Memory().Map()); |
| std::copy(indices.begin(), indices.end(), index_buffer_2_ptr + index_buffer_2_word_offset); |
| |
| index_buffer_2_ptr[5 + index_buffer_2_word_offset] = 2; |
| index_buffer_2_ptr[indices.size() - 1 + index_buffer_2_word_offset] = 1; |
| |
| index_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[1].SetTrianglesDeviceIndexBuffer(std::move(index_buffer_2), VK_INDEX_TYPE_UINT16); |
| const VkDeviceAddress index_buffer_addr = cube_blas.GetGeometries()[1].GetTrianglesDeviceIndexBuffer().Address(); |
| cube_blas.GetGeometries()[1].SetTrianglesIndexBufferDeviceAddress(index_buffer_addr + index_buffer_2_byte_offset); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 5.*was 3, but.*is 2"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03768", |
| "At offset 35.*was 2, but.*is 1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, VertexBufferUpdate) { |
| TEST_DESCRIPTION("Invalidly update a vertex from active to inactive, and inactive to active"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| struct Vertex { |
| float x, y, z; |
| }; |
| const std::array<Vertex, 9> vertices = {{ |
| {1.0f, 2.0f, 3.0f}, |
| {NAN, 5.0f, 6.0f}, |
| {7.0f, 8.0f, 9.0f}, |
| |
| {10.0f, 11.0f, 12.0f}, |
| {13.0, 14.0f, 15.0f}, |
| {16.0f, 17.0f, 18.0f}, |
| |
| {19.0f, 20.0f, 21.0f}, |
| {NAN, 22.0f, 23.0f}, |
| {24.0f, 25.0f, 26.0f}, |
| }}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer vertex_buffer(*m_device, sizeof(vertices[0]) * vertices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto vertex_buffer_ptr = static_cast<Vertex*>(vertex_buffer.Memory().Map()); |
| std::copy(vertices.begin(), vertices.end(), vertex_buffer_ptr); |
| vertex_buffer.Memory().Unmap(); |
| |
| vkt::as::GeometryKHR geom; |
| geom.SetType(vkt::as::GeometryKHR::Type::Triangle); |
| geom.SetFlags(VK_GEOMETRY_OPAQUE_BIT_KHR); |
| geom.SetPrimitiveCount(3); |
| geom.SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer), uint32_t(vertices.size() - 1)); |
| geom.SetTrianglesIndexType(VK_INDEX_TYPE_NONE_KHR); |
| // geom.SetTrianglesDeviceIndexBuffer(std::move(index_buffer), VK_INDEX_TYPE_UINT32); |
| |
| vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geom)); |
| blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| |
| m_command_buffer.Begin(); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| blas.SetSrcAS(blas.GetDstAS()); |
| blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| auto vertices_copy = vertices; |
| vertices_copy[0].x = NAN; |
| vertices_copy[1].x = 1.0f; |
| vertices_copy[vertices_copy.size() - 1].x = NAN; |
| vertices_copy[7].x = -42.0f; |
| vkt::Buffer vertex_buffer_2(*m_device, sizeof(vertices_copy[0]) * vertices_copy.size(), buffer_usage, kHostVisibleMemProps, |
| &alloc_flags); |
| auto vertex_buffer_2_ptr = static_cast<Vertex*>(vertex_buffer_2.Memory().Map()); |
| std::copy(vertices_copy.begin(), vertices_copy.end(), vertex_buffer_2_ptr); |
| vertex_buffer_2.Memory().Unmap(); |
| |
| blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer_2), uint32_t(vertices_copy.size() - 1)); |
| |
| m_command_buffer.Begin(); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 12 bytes, primitive was found at index 0 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 12 bytes, primitive was found at index 1 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 12 bytes, primitive was found at index 7 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 12 bytes, primitive was found at index 8 in vertex buffer"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Vertex buffer 3 identical to vertex_buffer, but starting at an offset |
| { |
| const uint32_t vertex_buffer_3_byte_offset = |
| 4 * vkuFormatTexelBlockSize(blas.GetGeometries()[0].GetVkObj().geometry.triangles.vertexFormat); |
| const uint32_t vertex_buffer_3_sizeof_vertex_offset = vertex_buffer_3_byte_offset / sizeof(Vertex); |
| vkt::Buffer vertex_buffer_3(*m_device, sizeof(vertices[0]) * vertices.size() + vertex_buffer_3_byte_offset, buffer_usage, |
| kHostVisibleMemProps, &alloc_flags); |
| auto vertex_buffer_3_ptr = static_cast<Vertex*>(vertex_buffer_3.Memory().Map()); |
| std::copy(vertices.begin(), vertices.end(), vertex_buffer_3_ptr + vertex_buffer_3_sizeof_vertex_offset); |
| vertex_buffer_3.Memory().Unmap(); |
| |
| blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer_3), uint32_t(vertices.size() - 1)); |
| auto build_range_infos = blas.GetBuildRangeInfosFromGeometries(); |
| build_range_infos[0].primitiveOffset = vertex_buffer_3_byte_offset; |
| blas.SetBuildRanges(build_range_infos); |
| |
| m_command_buffer.Begin(); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, VertexBufferUpdateStridedVerticesNoIndexBuffer) { |
| TEST_DESCRIPTION( |
| "Invalidly update a vertex from active to inactive, and inactive to active. Use an unusual vertex stride, and no index " |
| "buffer."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| struct Vertex { |
| float x, y, z; |
| }; |
| const std::array<Vertex, 9> vertices = {{ |
| {99.0f, 2.0f, 3.0f}, |
| {NAN, 5.0f, 6.0f}, |
| {7.0f, 8.0f, 9.0f}, |
| |
| {10.0f, 11.0f, 12.0f}, |
| {13.0, 14.0f, 15.0f}, |
| {16.0f, 17.0f, 18.0f}, |
| |
| {19.0f, 20.0f, 21.0f}, |
| {NAN, 22.0f, 23.0f}, |
| {24.0f, 25.0f, 26.0f}, |
| }}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| const uint32_t vertex_stride = 2 * 12; |
| |
| vkt::Buffer vertex_buffer(*m_device, vertex_stride * vertices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto vertex_buffer_ptr = static_cast<uint8_t*>(vertex_buffer.Memory().Map()); |
| |
| for (uint32_t vertex_i = 0; vertex_i < vertices.size(); ++vertex_i) { |
| std::memcpy(vertex_buffer_ptr + vertex_i * vertex_stride, vertices.data() + vertex_i, sizeof(Vertex)); |
| } |
| |
| vertex_buffer.Memory().Unmap(); |
| |
| vkt::as::GeometryKHR geom; |
| geom.SetType(vkt::as::GeometryKHR::Type::Triangle); |
| geom.SetFlags(VK_GEOMETRY_OPAQUE_BIT_KHR); |
| geom.SetPrimitiveCount(3); |
| geom.SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer), uint32_t(vertices.size() - 1), VK_FORMAT_R32G32B32_SFLOAT, |
| vertex_stride); |
| geom.SetTrianglesIndexType(VK_INDEX_TYPE_NONE_KHR); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geom)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| auto vertices_copy = vertices; |
| vertices_copy[0].x = NAN; |
| vertices_copy[1].x = 1.0f; |
| vertices_copy[7].x = -42.0f; |
| vertices_copy[8].x = NAN; |
| vkt::Buffer vertex_buffer_2(*m_device, vertex_stride * vertices_copy.size(), buffer_usage, kHostVisibleMemProps, |
| &alloc_flags); |
| auto vertex_buffer_2_ptr = static_cast<uint8_t*>(vertex_buffer_2.Memory().Map()); |
| for (uint32_t vertex_i = 0; vertex_i < vertices_copy.size(); ++vertex_i) { |
| std::memcpy(vertex_buffer_2_ptr + vertex_i * vertex_stride, vertices_copy.data() + vertex_i, sizeof(Vertex)); |
| } |
| |
| vertex_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer_2), uint32_t(vertices_copy.size() - 1), |
| VK_FORMAT_R32G32B32_SFLOAT, vertex_stride); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 0 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 1 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 7 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 8 in vertex buffer"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, VertexBufferUpdateStridedVerticesIndexBuffer) { |
| TEST_DESCRIPTION( |
| "Invalidly update a vertex from active to inactive, and inactive to active. Use an unusual vertex stride, and an index " |
| "buffer."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderInt64); |
| |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| struct Vertex { |
| float x, y, z; |
| }; |
| const std::array<Vertex, 9> vertices = {{ |
| {99.0f, 2.0f, 3.0f}, |
| {NAN, 5.0f, 6.0f}, |
| {7.0f, 8.0f, 9.0f}, |
| |
| {10.0f, 11.0f, 12.0f}, |
| {13.0, 14.0f, 15.0f}, |
| {16.0f, 17.0f, 18.0f}, |
| |
| {19.0f, 20.0f, 21.0f}, |
| {NAN, 22.0f, 23.0f}, |
| {24.0f, 25.0f, 26.0f}, |
| }}; |
| |
| const std::array<uint32_t, 9> indices = {{0, 1, 2, 3, 4, 5, 6, 7, 8}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| const uint32_t vertex_stride = 2 * 12; |
| |
| vkt::Buffer vertex_buffer(*m_device, vertex_stride * vertices.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto vertex_buffer_ptr = static_cast<uint8_t*>(vertex_buffer.Memory().Map()); |
| |
| for (uint32_t vertex_i = 0; vertex_i < vertices.size(); ++vertex_i) { |
| std::memcpy(vertex_buffer_ptr + vertex_i * vertex_stride, vertices.data() + vertex_i, sizeof(Vertex)); |
| } |
| |
| vertex_buffer.Memory().Unmap(); |
| |
| vkt::Buffer index_buffer(*m_device, indices.size() * sizeof(indices[0]), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| auto index_buffer_ptr = index_buffer.Memory().Map(); |
| |
| std::memcpy(index_buffer_ptr, indices.data(), indices.size() * sizeof(indices[0])); |
| |
| index_buffer.Memory().Unmap(); |
| |
| vkt::as::GeometryKHR geom; |
| geom.SetType(vkt::as::GeometryKHR::Type::Triangle); |
| geom.SetFlags(VK_GEOMETRY_OPAQUE_BIT_KHR); |
| geom.SetPrimitiveCount(3); |
| geom.SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer), uint32_t(vertices.size() - 1), VK_FORMAT_R32G32B32_SFLOAT, |
| vertex_stride); |
| geom.SetTrianglesDeviceIndexBuffer(std::move(index_buffer), VK_INDEX_TYPE_UINT32); |
| |
| vkt::as::BuildGeometryInfoKHR cube_blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geom)); |
| cube_blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| cube_blas.SetSrcAS(cube_blas.GetDstAS()); |
| cube_blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| { |
| auto vertices_copy = vertices; |
| vertices_copy[0].x = NAN; |
| vertices_copy[1].x = 1.0f; |
| vertices_copy[7].x = -42.0f; |
| vertices_copy[8].x = NAN; |
| vkt::Buffer vertex_buffer_2(*m_device, vertex_stride * vertices_copy.size(), buffer_usage, kHostVisibleMemProps, |
| &alloc_flags); |
| auto vertex_buffer_2_ptr = static_cast<uint8_t*>(vertex_buffer_2.Memory().Map()); |
| for (uint32_t vertex_i = 0; vertex_i < vertices_copy.size(); ++vertex_i) { |
| std::memcpy(vertex_buffer_2_ptr + vertex_i * vertex_stride, vertices_copy.data() + vertex_i, sizeof(Vertex)); |
| } |
| |
| vertex_buffer_2.Memory().Unmap(); |
| |
| cube_blas.GetGeometries()[0].SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer_2), uint32_t(vertices_copy.size() - 1), |
| VK_FORMAT_R32G32B32_SFLOAT, vertex_stride); |
| |
| m_command_buffer.Begin(); |
| cube_blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 0 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 1 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 7 in vertex buffer"); |
| m_errorMonitor->SetDesiredErrorRegex( |
| "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "vertices of format VK_FORMAT_R32G32B32_SFLOAT strided by 24 bytes, primitive was found at index 8 in vertex buffer"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, AabbStatusUpdate) { |
| TEST_DESCRIPTION("Change the active/inactive status of AABBs between a build and an update."); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayQuery); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| // Build Bottom Level Acceleration Structure |
| auto geometry = vkt::as::blueprint::GeometrySimpleOnDeviceAABBInfo(*m_device); |
| VkAabbPositionsKHR active_aabb; |
| active_aabb.minX = -1.0f; |
| active_aabb.maxX = 1.0f; |
| active_aabb.minY = -1.0f; |
| active_aabb.maxY = 1.0f; |
| active_aabb.minZ = -1.0f; |
| active_aabb.maxZ = 1.0f; |
| VkAabbPositionsKHR inactive_aabb = active_aabb; |
| inactive_aabb.minX = NAN; |
| std::array<VkAabbPositionsKHR, 6> aabbs = { |
| {active_aabb, inactive_aabb, inactive_aabb, active_aabb, active_aabb, inactive_aabb}}; |
| |
| VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper(); |
| alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| const VkBufferUsageFlags buffer_usage = |
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer aabbs_buffer(*m_device, sizeof(aabbs[0]) * aabbs.size(), buffer_usage, kHostVisibleMemProps, &alloc_flags); |
| |
| auto aabbs_buffer_ptr = static_cast<VkAabbPositionsKHR *>(aabbs_buffer.Memory().Map()); |
| std::copy(aabbs.begin(), aabbs.end(), aabbs_buffer_ptr); |
| |
| geometry.SetAABBsDeviceBuffer(std::move(aabbs_buffer)); |
| geometry.SetPrimitiveCount(size32(aabbs)); |
| |
| vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geometry)); |
| blas.AddFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR); |
| m_command_buffer.Begin(); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| |
| blas.SetSrcAS(blas.GetDstAS()); |
| blas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR); |
| |
| aabbs = {{inactive_aabb, inactive_aabb, active_aabb, inactive_aabb, active_aabb, active_aabb}}; |
| std::copy(aabbs.begin(), aabbs.end(), aabbs_buffer_ptr); |
| |
| blas.GetGeometries()[0].GetAABBs().device_buffer.Memory().Unmap(); |
| |
| m_command_buffer.Begin(); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "AABB primitive at index 0 strided by 24 bytes"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "AABB primitive at index 2 strided by 24 bytes"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03664", |
| "AABB primitive at index 3 strided by 24 bytes"); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03663", |
| "AABB primitive at index 5 strided by 24 bytes"); |
| m_default_queue->Submit(m_command_buffer); |
| m_device->Wait(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayMultipleTrianglesFlags) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // Multiple triangles flags, invalid |
| traceRayEXT(tlas, gl_RayFlagsCullBackFacingTrianglesEXT | gl_RayFlagsCullFrontFacingTrianglesEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06892", |
| "CullBackFacingTrianglesKHR|CullFrontFacingTrianglesKHR"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayMultipleOpaqueFlags) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // Multiple opaque flags, invalid |
| traceRayEXT(tlas, gl_RayFlagsCullOpaqueEXT | gl_RayFlagsCullNoOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTraceRayKHR-06893"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayMultipleTrianglesFlagsSlang) { |
| RETURN_IF_SKIP(CheckSlangSupport()); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* slang_shader = R"slang( |
| [[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas; |
| |
| struct RayPayload { float hit; }; |
| |
| [shader("raygeneration")] |
| void rayGenShader() |
| { |
| RayPayload ray_payload = {}; |
| RayDesc ray; |
| ray.Origin = float3(0, 0, 1); |
| ray.Direction = float3(0, 0, 1); |
| ray.TMin = 0.1; |
| ray.TMax = 1000.0; |
| // Multiple triangles flags, invalid |
| TraceRay(tlas, RAY_FLAG_CULL_BACK_FACING_TRIANGLES | RAY_FLAG_CULL_FRONT_FACING_TRIANGLES, 0xff, 0, 0, 0, ray, ray_payload); |
| } |
| |
| [shader("miss")] |
| void missShader(inout RayPayload payload) { payload.hit = 1.0; } |
| |
| [shader("closesthit")] |
| void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) { payload.hit = 1.0; } |
| )slang"; |
| pipeline.AddSlangRayGenShader(slang_shader, "rayGenShader"); |
| pipeline.AddSlangMissShader(slang_shader, "missShader"); |
| pipeline.AddSlangClosestHitShader(slang_shader, "closestHitShader"); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06892", |
| "CullBackFacingTrianglesKHR|CullFrontFacingTrianglesKHR"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayBothSkipFlags) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_EXT_ray_flags_primitive_culling : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // SkipTrianglesKHR and SkipAABBKHR are mutually exclusive, invalid |
| traceRayEXT(tlas, gl_RayFlagsSkipTrianglesEXT | gl_RayFlagsSkipAABBEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06552", "SkipTrianglesKHR|SkipAABBsKHR"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayOriginNonFinite) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float zero; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // 1.0 / 0.0 produces +infinity, invalid |
| float infinity = 1.0 / zero; |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,infinity,0), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| *static_cast<float*>(uniform_buffer.Memory().Map()) = 0.0f; |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06355", "0, inf, 0"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayDirectionNonFinite) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float zero; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // 1.0 / 0.0 produces +infinity, invalid |
| float infinity = 1.0 / zero; |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,infinity,2), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| *static_cast<float*>(uniform_buffer.Memory().Map()) = 0.0f; |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06355", "0, inf, 2"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayNegativeTmin) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float negative; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // negative Tmin, invalid |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), negative, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| *static_cast<float*>(uniform_buffer.Memory().Map()) = -1.0f; |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06356", "Tmin: -1, Tmax: 1000"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayNegativeTmax) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float negative; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // negative Tmax, invalid |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), negative, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| *static_cast<float*>(uniform_buffer.Memory().Map()) = -1.0f; |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06356", "Tmin: 0.1, Tmax: -1"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayTminGreaterThanTmax) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float t_min; float t_max; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // Tmin > Tmax, invalid |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), t_min, vec3(0,0,1), t_max, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, 2 * sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| auto* uniform_buffer_ptr = static_cast<float*>(uniform_buffer.Memory().Map()); |
| uniform_buffer_ptr[0] = 2.0f; // t_min |
| uniform_buffer_ptr[1] = 1.0f; // t_max |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06357", |
| "Ray Tmin \\(2\\) is greater than Ray Tmax \\(1\\)"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayTminAndTmaxNaNs) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(binding = 1, set = 0) uniform Params { float t_min; float t_max; }; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // Tmin and Tmax are NaNs, invalid |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), t_min, vec3(0,0,1), t_max, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| |
| vkt::Buffer uniform_buffer(*m_device, 2 * sizeof(float), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| auto* uniform_buffer_ptr = static_cast<float*>(uniform_buffer.Memory().Map()); |
| uniform_buffer_ptr[0] = NAN; // t_min |
| uniform_buffer_ptr[1] = NAN; // t_max |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06358", "Ray Tmin \\(nan\\) or Ray Tmax \\(nan\\)"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRayTlasNotBuilt) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 8, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| // tlas not yet built |
| traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 100.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 8); |
| pipeline.CreateDescriptorSet(); |
| |
| m_command_buffer.Begin(); |
| vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Record TLAS build, but don't submit it |
| m_command_buffer.Begin(); |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS()); |
| tlas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(8, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06359", "set = 0, binding = 8, index 0"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRaySkipTrianglesWithPipelineSkipAABBs) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::rayTraversalPrimitiveCulling); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags(VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_EXT_ray_flags_primitive_culling : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| traceRayEXT(tlas, gl_RayFlagsSkipTrianglesEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06553", "SkipTrianglesKHR"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpTraceRaySkipAABBsWithPipelineSkipTriangles) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::rayTraversalPrimitiveCulling); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags(VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| #extension GL_EXT_ray_flags_primitive_culling : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| traceRayEXT(tlas, gl_RayFlagsSkipAABBEXT, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| pipeline.AddGlslClosestHitShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.CreateDescriptorSet(); |
| vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer)); |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpTraceRayKHR-06554", "SkipAABBsKHR"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeGpuAVRayTracing, OpReportIntersectionKHRHitKindOutOfRange) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::accelerationStructure); |
| AddRequiredFeature(vkt::Feature::rayTracingPipeline); |
| AddRequiredFeature(vkt::Feature::rayTraversalPrimitiveCulling); |
| VkValidationFeaturesEXT validation_features = GetGpuAvValidationFeatures(); |
| RETURN_IF_SKIP(InitFrameworkForRayTracingTest(&validation_features)); |
| if (!CanEnableGpuAV(*this)) { |
| GTEST_SKIP() << "Requirements for GPU-AV are not met"; |
| } |
| RETURN_IF_SKIP(InitState()); |
| |
| vkt::rt::Pipeline pipeline(*this, m_device); |
| pipeline.AddCreateInfoFlags(VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR); |
| |
| const char* ray_gen = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas; |
| layout(location = 0) rayPayloadEXT vec3 hit; |
| |
| void main() { |
| traceRayEXT(tlas, 0, 0xff, 0, 0, 0, vec3(0,0,1), 0.1, vec3(0,0,1), 1000.0, 0); |
| } |
| )glsl"; |
| pipeline.SetGlslRayGenShader(ray_gen); |
| |
| const char* intersection = R"glsl( |
| #version 460 |
| #extension GL_EXT_ray_tracing : require |
| |
| layout(binding = 1, set = 0) buffer DbgBuffer { |
| uint intersection_invocation_count; |
| }; |
| |
| void main() { |
| atomicAdd(intersection_invocation_count, 1); |
| reportIntersectionEXT(1.0f, 128); |
| } |
| )glsl"; |
| pipeline.AddGlslHitGroupShader(kRayTracingPayloadMinimalGlsl, intersection); |
| pipeline.AddGlslMissShader(kRayTracingPayloadMinimalGlsl); |
| |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0); |
| pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); |
| pipeline.CreateDescriptorSet(); |
| |
| vkt::Buffer debug_buffer(*m_device, sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| kHostVisibleMemProps); |
| m_command_buffer.Begin(); |
| vk::CmdFillBuffer(m_command_buffer, debug_buffer, 0, debug_buffer.CreateInfo().size, 0); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| // Create acceleration structure |
| m_command_buffer.Begin(); |
| // Build Bottom Level Acceleration Structure |
| vkt::as::BuildGeometryInfoKHR blas = |
| vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::AABB); |
| blas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| m_command_buffer.Begin(); |
| // Build Top Level Acceleration Structure |
| vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS()); |
| tlas.BuildCmdBuffer(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle()); |
| pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipeline.GetDescriptorSet().UpdateDescriptorSets(); |
| |
| pipeline.Build(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1, |
| &pipeline.GetDescriptorSet().set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); |
| vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt(); |
| vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt, |
| &trace_rays_sbt.callable_sbt, 1, 1, 1); |
| m_command_buffer.End(); |
| m_errorMonitor->SetDesiredErrorRegex("VUID-RuntimeSpirv-OpReportIntersectionKHR-06998", "Hit Kind is 128"); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| m_errorMonitor->VerifyFound(); |
| |
| auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map()); |
| ASSERT_GT(debug_buffer_ptr[0], 0u) << "Intersection shader was never invoked"; |
| debug_buffer.Memory().Unmap(); |
| } |