blob: dafc54692b01dbba35dec329dc9138ed88089459 [file]
/* Copyright (c) 2023-2026 The Khronos Group Inc.
* Copyright (c) 2023-2026 Valve Corporation
* Copyright (c) 2023-2026 LunarG, 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vulkan/vulkan_core.h>
#include "layer_validation_tests.h"
#include "pipeline_helper.h"
#include "descriptor_helper.h"
#include "ray_tracing_objects.h"
#include "utils/math_utils.h"
void GpuAVRayQueryTest::InitGpuAVRayQuery(std::vector<VkLayerSettingEXT> layer_settings) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayQuery);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
}
class PositiveGpuAVRayQuery : public GpuAVRayQueryTest {};
TEST_F(PositiveGpuAVRayQuery, ComputeBasic) {
TEST_DESCRIPTION("Ray query in a compute shader");
RETURN_IF_SKIP(InitGpuAVRayQuery());
const char* shader_source = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, gl_RayFlagsTerminateOnFirstHitEXT, 0xff, vec3(0), 0.1, vec3(0,0,1), 1000.0);
rayQueryProceedEXT(query);
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2);
pipeline.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr};
pipeline.CreateComputePipeline();
// Add TLAS binding
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer);
pipeline.descriptor_set_.WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.descriptor_set_.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipeline_layout_, 0, 1,
&pipeline.descriptor_set_.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
TEST_F(PositiveGpuAVRayQuery, ComputeDynamicTminTmax) {
TEST_DESCRIPTION("Ray query in a compute shader, with dynamically set t_min and t_max");
RETURN_IF_SKIP(InitGpuAVRayQuery());
const char* shader_source = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 1) uniform Uniforms {
float t_min;
float t_max;
} trace_rays_params;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, gl_RayFlagsTerminateOnFirstHitEXT, 0xff, vec3(100000),
trace_rays_params.t_min, vec3(0,1,0), trace_rays_params.t_max);
rayQueryProceedEXT(query);
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2);
pipeline.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}};
pipeline.CreateComputePipeline();
// Add TLAS binding
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer);
pipeline.descriptor_set_.WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
// Add uniform buffer binding
vkt::Buffer uniform_buffer(*m_device, 4096, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
pipeline.descriptor_set_.WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE);
pipeline.descriptor_set_.UpdateDescriptorSets();
// Ray query with t_min dynamically set to 0
auto uniform_buffer_ptr = static_cast<float*>(uniform_buffer.Memory().Map());
{
uniform_buffer_ptr[0] = 0.0f; // t_min
uniform_buffer_ptr[1] = 42.0f; // t_max
}
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipeline_layout_, 0, 1,
&pipeline.descriptor_set_.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
// Ray query with both t_min and t_max dynamically set to 42
{
uniform_buffer_ptr[0] = 42.0f; // t_min
uniform_buffer_ptr[1] = 42.0f; // t_max
}
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
TEST_F(PositiveGpuAVRayQuery, ComputeDynamicRayFlags) {
TEST_DESCRIPTION("Ray query in a compute shader, with dynamically set ray flags");
RETURN_IF_SKIP(InitGpuAVRayQuery());
const char* shader_source = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 1) uniform Uniforms {
uint ray_query_flags;
} trace_rays_params;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, trace_rays_params.ray_query_flags, 0xff, vec3(0), 0.1, vec3(0,0,1), 42.0);
rayQueryProceedEXT(query);
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2);
pipeline.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}};
pipeline.CreateComputePipeline();
// Add TLAS binding
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer);
pipeline.descriptor_set_.WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
// Add uniform buffer binding
vkt::Buffer uniform_buffer(*m_device, 4096, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
pipeline.descriptor_set_.WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE);
pipeline.descriptor_set_.UpdateDescriptorSets();
// Ray query with t_min dynamically set to 0
{
auto uniform_buffer_ptr = static_cast<uint32_t*>(uniform_buffer.Memory().Map());
uniform_buffer_ptr[0] = 4u | 16u; // gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsCullBackFacingTrianglesEXT
}
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipeline_layout_, 0, 1,
&pipeline.descriptor_set_.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
TEST_F(PositiveGpuAVRayQuery, ComputeDynamicRayFlagsSkipTriangles) {
TEST_DESCRIPTION("Ray query in a compute shader, with dynamically set ray flags containing gl_RayFlagsSkipTrianglesEXT");
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTraversalPrimitiveCulling);
RETURN_IF_SKIP(InitGpuAVRayQuery());
const char* shader_source = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 1) uniform Uniforms {
uint ray_query_flags;
} trace_rays_params;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, trace_rays_params.ray_query_flags, 0xff, vec3(0), 0.1, vec3(0,0,1), 42.0);
rayQueryProceedEXT(query);
}
)glsl";
CreateComputePipelineHelper pipeline(*this);
pipeline.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2);
pipeline.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}};
pipeline.CreateComputePipeline();
// Add TLAS binding
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer);
pipeline.descriptor_set_.WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
// Add uniform buffer binding
vkt::Buffer uniform_buffer(*m_device, 4096, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
pipeline.descriptor_set_.WriteDescriptorBufferInfo(1, uniform_buffer, 0, VK_WHOLE_SIZE);
pipeline.descriptor_set_.UpdateDescriptorSets();
{
auto uniform_buffer_ptr = static_cast<uint32_t*>(uniform_buffer.Memory().Map());
uniform_buffer_ptr[0] = 4u | 0x100; // gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipTrianglesEXT
}
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.pipeline_layout_, 0, 1,
&pipeline.descriptor_set_.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
TEST_F(PositiveGpuAVRayQuery, GraphicsBasic) {
TEST_DESCRIPTION("Ray query in a vertex shader");
RETURN_IF_SKIP(InitGpuAVRayQuery());
InitRenderTarget();
const char* vertex_source = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, gl_RayFlagsTerminateOnFirstHitEXT, 0xff, vec3(0), 0.1, vec3(0,0,1), 1000.0);
rayQueryProceedEXT(query);
gl_Position = vec4(1);
}
)glsl";
VkShaderObj vs(*m_device, vertex_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipeline(*this);
pipeline.shader_stages_ = {vs.GetStageCreateInfo(), pipeline.fs_->GetStageCreateInfo()};
pipeline.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr};
pipeline.CreateGraphicsPipeline();
// Add TLAS binding
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer);
pipeline.descriptor_set_->WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline_layout_, 0, 1,
&pipeline.descriptor_set_->set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
}
TEST_F(PositiveGpuAVRayQuery, RayTracingBasic) {
TEST_DESCRIPTION("Ray query in a ray generation shader");
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
RETURN_IF_SKIP(InitGpuAVRayQuery());
vkt::rt::Pipeline pipeline(*this, m_device);
// Set ray gen shader
const char* ray_gen = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, gl_RayFlagsTerminateOnFirstHitEXT, 0xff, vec3(0), 0.1, vec3(0,0,1), 1000.0);
rayQueryProceedEXT(query);
}
)glsl";
pipeline.SetGlslRayGenShader(ray_gen);
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();
// Build pipeline
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(PositiveGpuAVRayQuery, Test) {
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::nullDescriptor);
RETURN_IF_SKIP(InitGpuAVRayQuery());
const char* rgen_source = R"glsl(
#version 460 core
#extension GL_EXT_ray_tracing : require
layout(location = 0) rayPayloadEXT vec3 hitValue;
layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;
void main() {
uint rayFlags = 0;
uint cullMask = 0xFF;
float tmin = 0.0;
float tmax = 9.0;
vec3 origin = vec3((float(gl_LaunchIDEXT.x) + 0.5f) / float(gl_LaunchSizeEXT.x), (float(gl_LaunchIDEXT.y) + 0.5f) / float(gl_LaunchSizeEXT.y), 0.0);
vec3 direct = vec3(0.0, 0.0, -1.0);
traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);
}
)glsl";
const char* ahit_source = R"glsl(
#version 460 core
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_ray_query : require
hitAttributeEXT vec3 attribs;
layout(location = 0) rayPayloadInEXT vec3 hitValue;
layout(set = 0, binding = 0, r32i) uniform iimage3D result;
layout(set = 0, binding = 2) uniform accelerationStructureEXT rayQueryTopLevelAccelerationStructure;
void main() {
ivec3 pos = ivec3(gl_LaunchIDEXT);
ivec3 size = ivec3(gl_LaunchSizeEXT);
uint rayFlags = 0;
uint cullMask = 0xFF;
float tmin = 0.0;
float tmax = 9.0;
vec3 origin = vec3((float(pos.x) + 0.5f) / float(size.x), (float(pos.y) + 0.5f) / float(size.y), 0.0);
vec3 direct = vec3(0.0, 0.0, -1.0);
uint value = 1;
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, rayQueryTopLevelAccelerationStructure, rayFlags, cullMask, origin, tmin, direct, tmax);
if (rayQueryProceedEXT(rayQuery)) {
value++;
rayQueryTerminateEXT(rayQuery);
}
imageStore(result, pos, ivec4(value, 0, 0, 0));
}
)glsl";
const char* chit_source = R"glsl(
#version 460 core
#extension GL_EXT_ray_tracing : require
hitAttributeEXT vec3 attribs;
layout(location = 0) rayPayloadInEXT vec3 hitValue;
void main() {
}
)glsl";
const char* miss_source = R"glsl(
#version 460 core
#extension GL_EXT_ray_tracing : require
layout(location = 0) rayPayloadInEXT vec3 hitValue;
void main() {
}
)glsl";
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_3D;
image_ci.format = VK_FORMAT_R32_SINT;
image_ci.extent = {8u, 8u, 8u};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (!IsImageFormatSupported(Gpu(), image_ci, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
GTEST_SKIP() << "VK_FORMAT_R32_SINT not supported";
}
vkt::Image result_image(*m_device, image_ci);
result_image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::ImageView result_view = result_image.CreateView(VK_IMAGE_VIEW_TYPE_3D, 0, VK_REMAINING_MIP_LEVELS, 0,
VK_REMAINING_ARRAY_LAYERS, VK_IMAGE_ASPECT_COLOR_BIT);
vkt::as::GeometryKHR geometry;
geometry.SetType(vkt::as::GeometryKHR::Type::Triangle);
float vertices[] = {
-1.0f, -1.0f, -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f,
};
VkMemoryAllocateFlagsInfo alloc_flags = vku::InitStructHelper();
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
const VkBufferUsageFlags geometry_buffer_usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
vkt::Buffer vertex_buffer(*m_device, sizeof(vertices), geometry_buffer_usage, kHostVisibleMemProps, &alloc_flags);
void* vertex_buffer_data = vertex_buffer.Memory().Map();
memcpy(vertex_buffer_data, vertices, sizeof(vertices));
vertex_buffer.Memory().Unmap();
const VkTransformMatrixKHR transform_matrix = {{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
}};
vkt::Buffer transform_buffer(*m_device, sizeof(transform_matrix), geometry_buffer_usage, kHostVisibleMemProps, &alloc_flags);
void* transform_buffer_data = transform_buffer.Memory().Map();
memcpy(transform_buffer_data, &transform_matrix, sizeof(transform_matrix));
transform_buffer.Memory().Unmap();
geometry.SetPrimitiveCount(2u);
geometry.SetTrianglesDeviceVertexBuffer(std::move(vertex_buffer), 5u);
geometry.SetTrianglesIndexType(VK_INDEX_TYPE_NONE_KHR);
geometry.SetTrianglesTransformBuffer(std::move(transform_buffer));
geometry.SetFlags(0u);
vkt::as::BuildGeometryInfoKHR blas = vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(geometry));
m_command_buffer.Begin();
blas.BuildCmdBuffer(m_command_buffer);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, *blas.GetDstAS());
m_command_buffer.Begin();
tlas.BuildCmdBuffer(m_command_buffer);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
const VkShaderStageFlags ray_tracing_stages = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR |
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR |
VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR;
OneOffDescriptorSet descriptor_set(m_device,
{{0u, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u, ray_tracing_stages, nullptr},
{1u, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, ray_tracing_stages, nullptr},
{2u, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, ray_tracing_stages, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
VkShaderObj rgen_shader(*m_device, rgen_source, VK_SHADER_STAGE_RAYGEN_BIT_KHR, SPV_ENV_VULKAN_1_2);
VkShaderObj ahit_shader(*m_device, ahit_source, VK_SHADER_STAGE_ANY_HIT_BIT_KHR, SPV_ENV_VULKAN_1_2);
VkShaderObj chit_shader(*m_device, chit_source, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, SPV_ENV_VULKAN_1_2);
VkShaderObj miss_shader(*m_device, miss_source, VK_SHADER_STAGE_MISS_BIT_KHR, SPV_ENV_VULKAN_1_2);
VkPipelineShaderStageCreateInfo stage_cis[4];
stage_cis[0] = vku::InitStructHelper();
stage_cis[0].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
stage_cis[0].module = rgen_shader;
stage_cis[0].pName = "main";
stage_cis[1] = vku::InitStructHelper();
stage_cis[1].stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stage_cis[1].module = ahit_shader;
stage_cis[1].pName = "main";
stage_cis[2] = vku::InitStructHelper();
stage_cis[2].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stage_cis[2].module = chit_shader;
stage_cis[2].pName = "main";
stage_cis[3] = vku::InitStructHelper();
stage_cis[3].stage = VK_SHADER_STAGE_MISS_BIT_KHR;
stage_cis[3].module = miss_shader;
stage_cis[3].pName = "main";
VkRayTracingShaderGroupCreateInfoKHR group_cis[3];
group_cis[0] = vku::InitStructHelper();
group_cis[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
group_cis[0].generalShader = 0u;
group_cis[0].closestHitShader = VK_SHADER_UNUSED_KHR;
group_cis[0].anyHitShader = VK_SHADER_UNUSED_KHR;
group_cis[0].intersectionShader = VK_SHADER_UNUSED_KHR;
group_cis[1] = vku::InitStructHelper();
group_cis[1].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
group_cis[1].generalShader = 3u;
group_cis[1].closestHitShader = VK_SHADER_UNUSED_KHR;
group_cis[1].anyHitShader = VK_SHADER_UNUSED_KHR;
group_cis[1].intersectionShader = VK_SHADER_UNUSED_KHR;
group_cis[2] = vku::InitStructHelper();
group_cis[2].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
group_cis[2].generalShader = VK_SHADER_UNUSED_KHR;
group_cis[2].closestHitShader = 2u;
group_cis[2].anyHitShader = 1u;
group_cis[2].intersectionShader = VK_SHADER_UNUSED_KHR;
const uint32_t group_count = 3;
VkRayTracingPipelineCreateInfoKHR pipeline_ci = vku::InitStructHelper();
pipeline_ci.stageCount = 4u;
pipeline_ci.pStages = stage_cis;
pipeline_ci.groupCount = group_count;
pipeline_ci.pGroups = group_cis;
pipeline_ci.maxPipelineRayRecursionDepth = 1u;
pipeline_ci.layout = pipeline_layout;
vkt::Pipeline rt_pipeline(*m_device, pipeline_ci);
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rt_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(rt_props);
const uint32_t sbt_entry_size = Align(rt_props.shaderGroupHandleSize, rt_props.shaderGroupBaseAlignment);
std::vector<uint8_t> shader_group_handles(rt_props.shaderGroupHandleSize * group_count);
vk::GetRayTracingShaderGroupHandlesKHR(device(), rt_pipeline, 0u, group_count, shader_group_handles.size(),
shader_group_handles.data());
vkt::Buffer sbt_buffer(*m_device, sbt_entry_size * group_count, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
vkt::device_address);
uint8_t* sbt_ptr = static_cast<uint8_t*>(sbt_buffer.Memory().Map());
for (uint32_t i = 0; i < group_count; ++i) {
memcpy(sbt_ptr + sbt_entry_size * i, shader_group_handles.data() + rt_props.shaderGroupHandleSize * i,
rt_props.shaderGroupHandleSize);
}
sbt_buffer.Memory().Unmap();
const VkDeviceAddress sbt_address = sbt_buffer.Address();
const VkStridedDeviceAddressRegionKHR raygen_sbt = {sbt_address, sbt_entry_size, sbt_entry_size};
const VkStridedDeviceAddressRegionKHR miss_sbt = {sbt_address + sbt_entry_size, sbt_entry_size, sbt_entry_size};
const VkStridedDeviceAddressRegionKHR hit_sbt = {sbt_address + 2u * sbt_entry_size, sbt_entry_size, sbt_entry_size};
const VkStridedDeviceAddressRegionKHR callable_sbt = {};
VkAccelerationStructureKHR tlas_handle = tlas.GetDstAS()->handle();
VkAccelerationStructureKHR null_as = VK_NULL_HANDLE;
descriptor_set.WriteDescriptorImageInfo(0, result_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
VK_IMAGE_LAYOUT_GENERAL);
descriptor_set.WriteDescriptorAccelStruct(1, 1, &tlas_handle);
descriptor_set.WriteDescriptorAccelStruct(2, 1, &null_as);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rt_pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline_layout, 0u, 1u,
&descriptor_set.set_, 0u, nullptr);
vk::CmdTraceRaysKHR(m_command_buffer, &raygen_sbt, &miss_sbt, &hit_sbt, &callable_sbt, 8u, 8u, 1u);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}