blob: ab817f51deda11092a587b1029b6cab77aa1e66c [file] [log] [blame]
/*
* Copyright (c) 2020-2025 The Khronos Group Inc.
* Copyright (c) 2020-2025 Valve Corporation
* Copyright (c) 2020-2025 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 "../framework/layer_validation_tests.h"
#include "../framework/descriptor_helper.h"
#include "../framework/ray_tracing_objects.h"
#include "../framework/shader_helper.h"
#include "../framework/gpu_av_helper.h"
class NegativeGpuAVRayTracing : public GpuAVRayTracingTest {};
TEST_F(NegativeGpuAVRayTracing, CmdTraceRaysIndirect) {
TEST_DESCRIPTION("Test debug printf in raygen shader.");
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);
// Create and fill buffers storing indirect data (ray query dimensions)
vkt::Buffer trace_rays_big_width(
*m_device, 4096, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 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_big_width.Memory().Unmap();
trace_rays_dim = {1, rt_pipeline_props.maxRayDispatchInvocationCount + 1, 1};
vkt::Buffer trace_rays_big_height(
*m_device, 4096, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 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_big_height.Memory().Unmap();
trace_rays_dim = {1, 1, rt_pipeline_props.maxRayDispatchInvocationCount + 1};
vkt::Buffer trace_ray_big_depth(*m_device, 4096, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
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));
trace_ray_big_depth.Memory().Unmap();
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.Handle());
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->Submit(m_command_buffer);
m_default_queue->Wait();
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();
uniform_buffer.Memory().Unmap();
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, uniform_buffer.handle(), 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.Handle());
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();
}