blob: 374e2380247efcd5b1b5ac40093011f684737c3e [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-2025 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 <vulkan/vulkan_core.h>
#include <cstdint>
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/shader_object_helper.h"
#include "../framework/descriptor_helper.h"
#include "../framework/buffer_helper.h"
#include "../framework/gpu_av_helper.h"
#include "../framework/ray_tracing_objects.h"
class NegativeDebugPrintfRayTracing : public DebugPrintfTests {
public:
void InitFrameworkWithPrintfBufferSize(uint32_t printf_buffer_size) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME);
VkBool32 printf_value = VK_TRUE;
VkLayerSettingEXT printf_enable_setting = {OBJECT_LAYER_NAME, "printf_enable", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1,
&printf_value};
VkLayerSettingEXT printf_buffer_size_setting = {OBJECT_LAYER_NAME, "printf_buffer_size", VK_LAYER_SETTING_TYPE_UINT32_EXT,
1, &printf_buffer_size};
std::array<VkLayerSettingEXT, 2> layer_settings = {printf_enable_setting, printf_buffer_size_setting};
VkLayerSettingsCreateInfoEXT layer_settings_create_info = vku::InitStructHelper();
layer_settings_create_info.settingCount = static_cast<uint32_t>(layer_settings.size());
layer_settings_create_info.pSettings = layer_settings.data();
RETURN_IF_SKIP(InitFramework(&layer_settings_create_info));
if (!CanEnableGpuAV(*this)) {
GTEST_SKIP() << "Requirements for GPU-AV/Printf are not met";
}
if (IsExtensionsEnabled(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
GTEST_SKIP() << "Currently disabled for Portability";
}
}
// Build Top Level Acceleration Structure:
// 2 instances of the cube, at different positions
// clang-format off
/*
cube instance 2, translation (x = 0, y = 0, z = 50)
+----+
| 2 |
+----+
Z
^
| +----+
+---> X | 1 | cube instance 1, translation (x = 50, y = 0, z = 0)
+----+
*/
// clang-format on
vkt::as::BuildGeometryInfoKHR GetCubesTLAS(std::shared_ptr<vkt::as::BuildGeometryInfoKHR>& out_cube_blas) {
vkt::as::GeometryKHR cube(vkt::as::blueprint::GeometryCubeOnDeviceInfo(*m_device));
out_cube_blas = std::make_shared<vkt::as::BuildGeometryInfoKHR>(
vkt::as::blueprint::BuildGeometryInfoOnDeviceBottomLevel(*m_device, std::move(cube)));
// Build Bottom Level Acceleration Structure
m_command_buffer.Begin();
out_cube_blas->BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
vkt::as::BuildGeometryInfoKHR tlas(m_device);
tlas.SetType(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR);
tlas.SetBuildType(VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR);
tlas.SetMode(VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR);
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, out_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 2
cube_instance_2.instanceShaderBindingTableRecordOffset = 1;
cube_instances[0].AddInstanceDeviceAccelStructRef(*m_device, out_cube_blas->GetDstAS()->handle(), cube_instance_2);
tlas.SetGeometries(std::move(cube_instances));
tlas.SetBuildRanges(tlas.GetBuildRangeInfosFromGeometries());
// Set source and destination acceleration structures info. Does not create handles, it is done in Build()
tlas.SetSrcAS(vkt::as::blueprint::AccelStructNull(*m_device));
auto dstAsSize = tlas.GetSizeInfo().accelerationStructureSize;
auto dst_as = vkt::as::blueprint::AccelStructSimpleOnDeviceBottomLevel(*m_device, dstAsSize);
dst_as->SetType(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR);
tlas.SetDstAS(std::move(dst_as));
tlas.SetUpdateDstAccelStructSizeBeforeBuild(true);
tlas.SetInfoCount(1);
tlas.SetNullInfos(false);
tlas.SetNullBuildRangeInfos(false);
m_command_buffer.Begin();
tlas.BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
return tlas;
}
};
const char* GetSlangShader1() {
// slang shader. Compiled with:
// slangc.exe -capability GL_EXT_debug_printf .\ray_tracing.slang -target spirv-asm -profile glsl_460 -O0 -o ray_tracing.spv
// /!\ /!\ /!\ you need to manually edit the OpEntryPoint in the resulting spir-v to match the slang shader
/*
[[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas;
[[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer;
struct RayPayload {
float3 hit;
};
[shader("raygeneration")]
void rayGenShader()
{
printf("In Raygen 1");
InterlockedAdd(debug_buffer[0], 1);
RayPayload ray_payload = { float3(0) };
RayDesc ray;
ray.TMin = 0.01;
ray.TMax = 1000.0;
// Will miss
ray.Origin = float3(0,0,0);
ray.Direction = float3(0,0,-1);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload);
// 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 miss
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("raygeneration")]
void rayGenShader2()
{
printf("In Raygen 2");
InterlockedAdd(debug_buffer[1], 1);
RayPayload ray_payload = { float3(0) };
RayDesc ray;
ray.TMin = 0.01;
ray.TMax = 1000.0;
// Will hit cube 1
ray.Origin = float3(-50,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)
{
printf("In Miss 1");
InterlockedAdd(debug_buffer[2], 1);
payload.hit = float3(0.1, 0.2, 0.3);
}
[shader("miss")]
void missShader2(inout RayPayload payload)
{
printf("In Miss 2");
InterlockedAdd(debug_buffer[3], 1);
payload.hit = float3(42, 42, 42);
}
[shader("closesthit")]
void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
printf("In Closest Hit 1");
InterlockedAdd(debug_buffer[4], 1);
const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x,
attr.barycentrics.y); payload.hit = barycentric_coords;
RayPayload ray_payload = { float3(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, ray_payload);
// Supposed to miss, and call missShader2
ray.Origin = float3(0,0,0);
ray.Direction = float3(0,1,0);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, miss_shader_i, ray, ray_payload);
}
[shader("closesthit")]
void closestHitShader2(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
printf("In Closest Hit 2");
InterlockedAdd(debug_buffer[5], 1);
const float3 barycentric_coords = float3(1.0f - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x,
attr.barycentrics.y); payload.hit = 999 * barycentric_coords;
}
*/
const char* ray_tracing_pipeline_spv = R"asm(
; SPIR-V
; Version: 1.5
; Generator: Khronos; 40
; Bound: 236
; Schema: 0
OpCapability RayTracingKHR
OpCapability Shader
OpExtension "SPV_KHR_non_semantic_info"
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpExtension "SPV_KHR_ray_tracing"
%11 = OpExtInstImport "NonSemantic.DebugPrintf"
OpMemoryModel Logical GLSL450
OpEntryPoint RayGenerationKHR %rayGenShader "rayGenShader" %p %debug_buffer %tlas
OpEntryPoint RayGenerationKHR %rayGenShader2 "rayGenShader2" %p %debug_buffer %tlas
OpEntryPoint MissKHR %missShader "missShader" %debug_buffer %136
OpEntryPoint MissKHR %missShader2 "missShader2" %debug_buffer %151
OpEntryPoint ClosestHitKHR %closestHitShader "closestHitShader" %p %debug_buffer %tlas %178 %168
OpEntryPoint ClosestHitKHR %closestHitShader2 "closestHitShader2" %debug_buffer %230 %221
; Debug Information
OpSource Slang 1
%12 = OpString "In Raygen 1"
%91 = OpString "In Raygen 2"
%132 = OpString "In Miss 1"
%148 = OpString "In Miss 2"
%161 = OpString "In Closest Hit 1"
%217 = OpString "In Closest Hit 2"
OpName %RayDesc "RayDesc" ; id %5
OpMemberName %RayDesc 0 "Origin"
OpMemberName %RayDesc 1 "TMin"
OpMemberName %RayDesc 2 "Direction"
OpMemberName %RayDesc 3 "TMax"
OpName %ray "ray" ; id %9
OpName %ray "ray" ; id %9
OpName %RWStructuredBuffer "RWStructuredBuffer" ; id %18
OpName %debug_buffer "debug_buffer" ; id %21
OpName %RayPayload "RayPayload" ; id %27
OpMemberName %RayPayload 0 "hit"
OpName %ray_payload "ray_payload" ; id %28
OpName %p "p" ; id %49
OpName %tlas "tlas" ; id %58
OpName %ray_payload_0 "ray_payload" ; id %61
OpName %ray_payload_1 "ray_payload" ; id %74
OpName %rayGenShader "rayGenShader" ; id %2
OpName %ray_0 "ray" ; id %89
OpName %ray_0 "ray" ; id %89
OpName %ray_payload_2 "ray_payload" ; id %95
OpName %ray_payload_3 "ray_payload" ; id %115
OpName %rayGenShader2 "rayGenShader2" ; id %87
OpName %missShader "missShader" ; id %129
OpName %missShader2 "missShader2" ; id %145
OpName %ray_1 "ray" ; id %159
OpName %ray_1 "ray" ; id %159
OpName %BuiltInTriangleIntersectionAttributes "BuiltInTriangleIntersectionAttributes" ; id %165
OpMemberName %BuiltInTriangleIntersectionAttributes 0 "barycentrics"
OpName %barycentric_coords "barycentric_coords" ; id %177
OpName %ray_payload_4 "ray_payload" ; id %182
OpName %ray_payload_5 "ray_payload" ; id %201
OpName %closestHitShader "closestHitShader" ; id %157
OpName %barycentric_coords_0 "barycentric_coords" ; id %229
OpName %closestHitShader2 "closestHitShader2" ; id %214
; Annotations
OpMemberDecorate %RayDesc 0 Offset 0
OpMemberDecorate %RayDesc 1 Offset 12
OpMemberDecorate %RayDesc 2 Offset 16
OpMemberDecorate %RayDesc 3 Offset 28
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %RWStructuredBuffer Block
OpMemberDecorate %RWStructuredBuffer 0 Offset 0
OpDecorate %debug_buffer Binding 1
OpDecorate %debug_buffer DescriptorSet 0
OpMemberDecorate %RayPayload 0 Offset 0
OpDecorate %p Location 0
OpDecorate %tlas Binding 0
OpDecorate %tlas DescriptorSet 0
OpMemberDecorate %BuiltInTriangleIntersectionAttributes 0 Offset 0
; Types, variables and constants
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%RayDesc = OpTypeStruct %v3float %float %v3float %float
%_ptr_Function_RayDesc = OpTypePointer Function %RayDesc
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
%_runtimearr_uint = OpTypeRuntimeArray %uint ; ArrayStride 4
%RWStructuredBuffer = OpTypeStruct %_runtimearr_uint ; Block
%_ptr_StorageBuffer_RWStructuredBuffer = OpTypePointer StorageBuffer %RWStructuredBuffer
%uint_1 = OpConstant %uint 1
%uint_0 = OpConstant %uint 0
%float_0 = OpConstant %float 0
%25 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%RayPayload = OpTypeStruct %v3float
%int_1 = OpConstant %int 1
%_ptr_Function_float = OpTypePointer Function %float
%float_0_00999999978 = OpConstant %float 0.00999999978
%int_3 = OpConstant %int 3
%float_1000 = OpConstant %float 1000
%_ptr_Function_v3float = OpTypePointer Function %v3float
%40 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%int_2 = OpConstant %int 2
%float_n1 = OpConstant %float -1
%44 = OpConstantComposite %v3float %float_0 %float_0 %float_n1
%_ptr_RayPayloadKHR_RayPayload = OpTypePointer RayPayloadKHR %RayPayload
%55 = OpTypeAccelerationStructureKHR
%_ptr_UniformConstant_55 = OpTypePointer UniformConstant %55
%uint_255 = OpConstant %uint 255
%float_1 = OpConstant %float 1
%63 = OpConstantComposite %v3float %float_1 %float_0 %float_0
%76 = OpConstantComposite %v3float %float_n1 %float_0 %float_0
%94 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%float_n50 = OpConstant %float -50
%101 = OpConstantComposite %v3float %float_n50 %float_0 %float_0
%105 = OpConstantComposite %v3float %float_1 %float_0 %float_0
%116 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%118 = OpConstantComposite %v3float %float_0 %float_0 %float_1
%_ptr_IncomingRayPayloadKHR_RayPayload = OpTypePointer IncomingRayPayloadKHR %RayPayload
%_ptr_IncomingRayPayloadKHR_v3float = OpTypePointer IncomingRayPayloadKHR %v3float
%float_0_100000001 = OpConstant %float 0.100000001
%float_0_200000003 = OpConstant %float 0.200000003
%float_0_300000012 = OpConstant %float 0.300000012
%139 = OpConstantComposite %v3float %float_0_100000001 %float_0_200000003 %float_0_300000012
%float_42 = OpConstant %float 42
%153 = OpConstantComposite %v3float %float_42 %float_42 %float_42
%int_4 = OpConstant %int 4
%v2float = OpTypeVector %float 2
%BuiltInTriangleIntersectionAttributes = OpTypeStruct %v2float
%_ptr_HitAttributeKHR_BuiltInTriangleIntersectionAttributes = OpTypePointer HitAttributeKHR %BuiltInTriangleIntersectionAttributes
%_ptr_HitAttributeKHR_v2float = OpTypePointer HitAttributeKHR %v2float
%181 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%188 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%191 = OpConstantComposite %v3float %float_0 %float_0 %float_1
%203 = OpConstantComposite %v3float %float_0 %float_1 %float_0
%int_5 = OpConstant %int 5
%float_999 = OpConstant %float 999
%debug_buffer = OpVariable %_ptr_StorageBuffer_RWStructuredBuffer StorageBuffer ; Binding 1, DescriptorSet 0
%p = OpVariable %_ptr_RayPayloadKHR_RayPayload RayPayloadKHR ; Location 0
%tlas = OpVariable %_ptr_UniformConstant_55 UniformConstant ; Binding 0, DescriptorSet 0
%136 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
%151 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
%168 = OpVariable %_ptr_HitAttributeKHR_BuiltInTriangleIntersectionAttributes HitAttributeKHR
%178 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
%221 = OpVariable %_ptr_HitAttributeKHR_BuiltInTriangleIntersectionAttributes HitAttributeKHR
%230 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
; Function rayGenShader
%rayGenShader = OpFunction %void None %3
%4 = OpLabel
%ray = OpVariable %_ptr_Function_RayDesc Function
%10 = OpExtInst %void %11 1 %12
%17 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_0
%22 = OpAtomicIAdd %uint %17 %uint_1 %uint_0 %uint_1
%ray_payload = OpCompositeConstruct %RayPayload %25
%31 = OpAccessChain %_ptr_Function_float %ray %int_1
OpStore %31 %float_0_00999999978
%35 = OpAccessChain %_ptr_Function_float %ray %int_3
OpStore %35 %float_1000
%39 = OpAccessChain %_ptr_Function_v3float %ray %int_0
OpStore %39 %40
%43 = OpAccessChain %_ptr_Function_v3float %ray %int_2
OpStore %43 %44
%47 = OpLoad %RayDesc %ray
OpStore %p %ray_payload
%51 = OpCompositeExtract %v3float %47 0
%52 = OpCompositeExtract %v3float %47 2
%53 = OpCompositeExtract %float %47 1
%54 = OpCompositeExtract %float %47 3
%56 = OpLoad %55 %tlas
OpTraceRayKHR %56 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %51 %53 %52 %54 %p
%ray_payload_0 = OpLoad %RayPayload %p
OpStore %39 %40
OpStore %43 %63
%66 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_0
%68 = OpCompositeExtract %v3float %66 0
%69 = OpCompositeExtract %v3float %66 2
%70 = OpCompositeExtract %float %66 1
%71 = OpCompositeExtract %float %66 3
%72 = OpLoad %55 %tlas
OpTraceRayKHR %72 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %68 %70 %69 %71 %p
%ray_payload_1 = OpLoad %RayPayload %p
OpStore %39 %40
OpStore %43 %76
%78 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_1
%80 = OpCompositeExtract %v3float %78 0
%81 = OpCompositeExtract %v3float %78 2
%82 = OpCompositeExtract %float %78 1
%83 = OpCompositeExtract %float %78 3
%84 = OpLoad %55 %tlas
OpTraceRayKHR %84 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %80 %82 %81 %83 %p
OpReturn
OpFunctionEnd
; Function rayGenShader2
%rayGenShader2 = OpFunction %void None %3
%88 = OpLabel
%ray_0 = OpVariable %_ptr_Function_RayDesc Function
%90 = OpExtInst %void %11 1 %91
%92 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_1
%93 = OpAtomicIAdd %uint %92 %uint_1 %uint_0 %uint_1
%ray_payload_2 = OpCompositeConstruct %RayPayload %94
%96 = OpAccessChain %_ptr_Function_float %ray_0 %int_1
OpStore %96 %float_0_00999999978
%98 = OpAccessChain %_ptr_Function_float %ray_0 %int_3
OpStore %98 %float_1000
%100 = OpAccessChain %_ptr_Function_v3float %ray_0 %int_0
OpStore %100 %101
%104 = OpAccessChain %_ptr_Function_v3float %ray_0 %int_2
OpStore %104 %105
%107 = OpLoad %RayDesc %ray_0
OpStore %p %ray_payload_2
%109 = OpCompositeExtract %v3float %107 0
%110 = OpCompositeExtract %v3float %107 2
%111 = OpCompositeExtract %float %107 1
%112 = OpCompositeExtract %float %107 3
%113 = OpLoad %55 %tlas
OpTraceRayKHR %113 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %109 %111 %110 %112 %p
%ray_payload_3 = OpLoad %RayPayload %p
OpStore %100 %116
OpStore %104 %118
%120 = OpLoad %RayDesc %ray_0
OpStore %p %ray_payload_3
%122 = OpCompositeExtract %v3float %120 0
%123 = OpCompositeExtract %v3float %120 2
%124 = OpCompositeExtract %float %120 1
%125 = OpCompositeExtract %float %120 3
%126 = OpLoad %55 %tlas
OpTraceRayKHR %126 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %122 %124 %123 %125 %p
OpReturn
OpFunctionEnd
; Function missShader
%missShader = OpFunction %void None %3
%130 = OpLabel
%131 = OpExtInst %void %11 1 %132
%133 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_2
%134 = OpAtomicIAdd %uint %133 %uint_1 %uint_0 %uint_1
%138 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %136 %int_0
OpStore %138 %139
OpReturn
OpFunctionEnd
; Function missShader2
%missShader2 = OpFunction %void None %3
%146 = OpLabel
%147 = OpExtInst %void %11 1 %148
%149 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_3
%150 = OpAtomicIAdd %uint %149 %uint_1 %uint_0 %uint_1
%152 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %151 %int_0
OpStore %152 %153
OpReturn
OpFunctionEnd
; Function closestHitShader
%closestHitShader = OpFunction %void None %3
%158 = OpLabel
%ray_1 = OpVariable %_ptr_Function_RayDesc Function
%160 = OpExtInst %void %11 1 %161
%163 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_4
%164 = OpAtomicIAdd %uint %163 %uint_1 %uint_0 %uint_1
%170 = OpAccessChain %_ptr_HitAttributeKHR_v2float %168 %int_0
%171 = OpLoad %v2float %170
%172 = OpCompositeExtract %float %171 0
%173 = OpFSub %float %float_1 %172
%174 = OpLoad %v2float %170
%175 = OpCompositeExtract %float %174 1
%176 = OpFSub %float %173 %175
%barycentric_coords = OpCompositeConstruct %v3float %176 %172 %175
%179 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %178 %int_0
OpStore %179 %barycentric_coords
%ray_payload_4 = OpCompositeConstruct %RayPayload %181
%183 = OpAccessChain %_ptr_Function_float %ray_1 %int_1
OpStore %183 %float_0_00999999978
%185 = OpAccessChain %_ptr_Function_float %ray_1 %int_3
OpStore %185 %float_1000
%187 = OpAccessChain %_ptr_Function_v3float %ray_1 %int_0
OpStore %187 %188
%190 = OpAccessChain %_ptr_Function_v3float %ray_1 %int_2
OpStore %190 %191
%193 = OpLoad %RayDesc %ray_1
OpStore %p %ray_payload_4
%195 = OpCompositeExtract %v3float %193 0
%196 = OpCompositeExtract %v3float %193 2
%197 = OpCompositeExtract %float %193 1
%198 = OpCompositeExtract %float %193 3
%199 = OpLoad %55 %tlas
OpTraceRayKHR %199 %uint_0 %uint_255 %uint_0 %uint_0 %uint_1 %195 %197 %196 %198 %p
%ray_payload_5 = OpLoad %RayPayload %p
OpStore %187 %188
OpStore %190 %203
%205 = OpLoad %RayDesc %ray_1
OpStore %p %ray_payload_5
%207 = OpCompositeExtract %v3float %205 0
%208 = OpCompositeExtract %v3float %205 2
%209 = OpCompositeExtract %float %205 1
%210 = OpCompositeExtract %float %205 3
%211 = OpLoad %55 %tlas
OpTraceRayKHR %211 %uint_0 %uint_255 %uint_0 %uint_0 %uint_1 %207 %209 %208 %210 %p
OpReturn
OpFunctionEnd
; Function closestHitShader2
%closestHitShader2 = OpFunction %void None %3
%215 = OpLabel
%216 = OpExtInst %void %11 1 %217
%219 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_5
%220 = OpAtomicIAdd %uint %219 %uint_1 %uint_0 %uint_1
%222 = OpAccessChain %_ptr_HitAttributeKHR_v2float %221 %int_0
%223 = OpLoad %v2float %222
%224 = OpCompositeExtract %float %223 0
%225 = OpFSub %float %float_1 %224
%226 = OpLoad %v2float %222
%227 = OpCompositeExtract %float %226 1
%228 = OpFSub %float %225 %227
%barycentric_coords_0 = OpCompositeConstruct %v3float %228 %224 %227
%231 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %230 %int_0
%232 = OpVectorTimesScalar %v3float %barycentric_coords_0 %float_999
OpStore %231 %232
OpReturn
OpFunctionEnd
)asm";
return ray_tracing_pipeline_spv;
}
const char* GetSlangShader2() {
// slang shader. Compiled with:
// slangc.exe -capability GL_EXT_debug_printf .\ray_tracing.slang -target spirv-asm -profile glsl_460 -O0 -o ray_tracing.spv
/*
[[vk::binding(0, 0)]] uniform RaytracingAccelerationStructure tlas;
[[vk::binding(1, 0)]] RWStructuredBuffer<uint32_t> debug_buffer;
struct RayPayload {
float3 hit;
};
[shader("raygeneration")]
void rayGenShader()
{
printf("In Raygen");
InterlockedAdd(debug_buffer[0], 1);
RayPayload ray_payload = { float3(0) };
RayDesc ray;
ray.TMin = 0.01;
ray.TMax = 1000.0;
// Will hit
ray.Origin = float3(0,0,-50);
ray.Direction = float3(0,0,1);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload);
// Will miss
ray.Origin = float3(0,0,-50);
ray.Direction = float3(0,0,-1);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload);
// Will miss
ray.Origin = float3(0,0,50);
ray.Direction = float3(0,0,1);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload);
// Will miss
ray.Origin = float3(0,0,50);
ray.Direction = float3(0,0,-1);
TraceRay(tlas, RAY_FLAG_NONE, 0xff, 0, 0, 0, ray, ray_payload);
// Will miss
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)
{
printf("In Miss");
InterlockedAdd(debug_buffer[1], 1);
payload.hit = float3(0.1, 0.2, 0.3);
}
[shader("closesthit")]
void closestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
printf("In Closest Hit");
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;
}
*/
const char* ray_tracing_pipeline_spv = R"asm(
; SPIR-V
; Version: 1.5
; Generator: Khronos; 40
; Bound: 151
; Schema: 0
OpCapability RayTracingKHR
OpCapability Shader
OpExtension "SPV_KHR_non_semantic_info"
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpExtension "SPV_KHR_ray_tracing"
%11 = OpExtInstImport "NonSemantic.DebugPrintf"
OpMemoryModel Logical GLSL450
OpEntryPoint RayGenerationKHR %rayGenShader "main" %p %debug_buffer %tlas
OpEntryPoint MissKHR %missShader "main" %debug_buffer %119
OpEntryPoint ClosestHitKHR %closestHitShader "main" %debug_buffer %147 %137
; Debug Information
OpSource Slang 1
%12 = OpString "In Raygen"
%115 = OpString "In Miss"
%131 = OpString "In Closest Hit"
OpName %RayDesc "RayDesc" ; id %5
OpMemberName %RayDesc 0 "Origin"
OpMemberName %RayDesc 1 "TMin"
OpMemberName %RayDesc 2 "Direction"
OpMemberName %RayDesc 3 "TMax"
OpName %ray "ray" ; id %9
OpName %ray "ray" ; id %9
OpName %RWStructuredBuffer "RWStructuredBuffer" ; id %18
OpName %debug_buffer "debug_buffer" ; id %21
OpName %RayPayload "RayPayload" ; id %27
OpMemberName %RayPayload 0 "hit"
OpName %ray_payload "ray_payload" ; id %28
OpName %p "p" ; id %50
OpName %tlas "tlas" ; id %59
OpName %ray_payload_0 "ray_payload" ; id %62
OpName %ray_payload_1 "ray_payload" ; id %75
OpName %ray_payload_2 "ray_payload" ; id %88
OpName %ray_payload_3 "ray_payload" ; id %99
OpName %rayGenShader "rayGenShader" ; id %2
OpName %missShader "missShader" ; id %112
OpName %BuiltInTriangleIntersectionAttributes "BuiltInTriangleIntersectionAttributes" ; id %134
OpMemberName %BuiltInTriangleIntersectionAttributes 0 "barycentrics"
OpName %barycentric_coords "barycentric_coords" ; id %146
OpName %closestHitShader "closestHitShader" ; id %128
; Annotations
OpMemberDecorate %RayDesc 0 Offset 0
OpMemberDecorate %RayDesc 1 Offset 12
OpMemberDecorate %RayDesc 2 Offset 16
OpMemberDecorate %RayDesc 3 Offset 28
OpDecorate %_runtimearr_uint ArrayStride 4
OpDecorate %RWStructuredBuffer Block
OpMemberDecorate %RWStructuredBuffer 0 Offset 0
OpDecorate %debug_buffer Binding 1
OpDecorate %debug_buffer DescriptorSet 0
OpMemberDecorate %RayPayload 0 Offset 0
OpDecorate %p Location 0
OpDecorate %tlas Binding 0
OpDecorate %tlas DescriptorSet 0
OpMemberDecorate %BuiltInTriangleIntersectionAttributes 0 Offset 0
; Types, variables and constants
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%RayDesc = OpTypeStruct %v3float %float %v3float %float
%_ptr_Function_RayDesc = OpTypePointer Function %RayDesc
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
%_runtimearr_uint = OpTypeRuntimeArray %uint ; ArrayStride 4
%RWStructuredBuffer = OpTypeStruct %_runtimearr_uint ; Block
%_ptr_StorageBuffer_RWStructuredBuffer = OpTypePointer StorageBuffer %RWStructuredBuffer
%uint_1 = OpConstant %uint 1
%uint_0 = OpConstant %uint 0
%float_0 = OpConstant %float 0
%25 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%RayPayload = OpTypeStruct %v3float
%int_1 = OpConstant %int 1
%_ptr_Function_float = OpTypePointer Function %float
%float_0_00999999978 = OpConstant %float 0.00999999978
%int_3 = OpConstant %int 3
%float_1000 = OpConstant %float 1000
%_ptr_Function_v3float = OpTypePointer Function %v3float
%float_n50 = OpConstant %float -50
%40 = OpConstantComposite %v3float %float_0 %float_0 %float_n50
%int_2 = OpConstant %int 2
%float_1 = OpConstant %float 1
%45 = OpConstantComposite %v3float %float_0 %float_0 %float_1
%_ptr_RayPayloadKHR_RayPayload = OpTypePointer RayPayloadKHR %RayPayload
%56 = OpTypeAccelerationStructureKHR
%_ptr_UniformConstant_56 = OpTypePointer UniformConstant %56
%uint_255 = OpConstant %uint 255
%float_n1 = OpConstant %float -1
%64 = OpConstantComposite %v3float %float_0 %float_0 %float_n1
%float_50 = OpConstant %float 50
%76 = OpConstantComposite %v3float %float_0 %float_0 %float_50
%100 = OpConstantComposite %v3float %float_0 %float_0 %float_0
%_ptr_IncomingRayPayloadKHR_RayPayload = OpTypePointer IncomingRayPayloadKHR %RayPayload
%_ptr_IncomingRayPayloadKHR_v3float = OpTypePointer IncomingRayPayloadKHR %v3float
%float_0_100000001 = OpConstant %float 0.100000001
%float_0_200000003 = OpConstant %float 0.200000003
%float_0_300000012 = OpConstant %float 0.300000012
%122 = OpConstantComposite %v3float %float_0_100000001 %float_0_200000003 %float_0_300000012
%v2float = OpTypeVector %float 2
%BuiltInTriangleIntersectionAttributes = OpTypeStruct %v2float
%_ptr_HitAttributeKHR_BuiltInTriangleIntersectionAttributes = OpTypePointer HitAttributeKHR %BuiltInTriangleIntersectionAttributes
%_ptr_HitAttributeKHR_v2float = OpTypePointer HitAttributeKHR %v2float
%debug_buffer = OpVariable %_ptr_StorageBuffer_RWStructuredBuffer StorageBuffer ; Binding 1, DescriptorSet 0
%p = OpVariable %_ptr_RayPayloadKHR_RayPayload RayPayloadKHR ; Location 0
%tlas = OpVariable %_ptr_UniformConstant_56 UniformConstant ; Binding 0, DescriptorSet 0
%119 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
%137 = OpVariable %_ptr_HitAttributeKHR_BuiltInTriangleIntersectionAttributes HitAttributeKHR
%147 = OpVariable %_ptr_IncomingRayPayloadKHR_RayPayload IncomingRayPayloadKHR
; Function rayGenShader
%rayGenShader = OpFunction %void None %3
%4 = OpLabel
%ray = OpVariable %_ptr_Function_RayDesc Function
%10 = OpExtInst %void %11 1 %12
%17 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_0
%22 = OpAtomicIAdd %uint %17 %uint_1 %uint_0 %uint_1
%ray_payload = OpCompositeConstruct %RayPayload %25
%31 = OpAccessChain %_ptr_Function_float %ray %int_1
OpStore %31 %float_0_00999999978
%35 = OpAccessChain %_ptr_Function_float %ray %int_3
OpStore %35 %float_1000
%39 = OpAccessChain %_ptr_Function_v3float %ray %int_0
OpStore %39 %40
%44 = OpAccessChain %_ptr_Function_v3float %ray %int_2
OpStore %44 %45
%48 = OpLoad %RayDesc %ray
OpStore %p %ray_payload
%52 = OpCompositeExtract %v3float %48 0
%53 = OpCompositeExtract %v3float %48 2
%54 = OpCompositeExtract %float %48 1
%55 = OpCompositeExtract %float %48 3
%57 = OpLoad %56 %tlas
OpTraceRayKHR %57 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %52 %54 %53 %55 %p
%ray_payload_0 = OpLoad %RayPayload %p
OpStore %39 %40
OpStore %44 %64
%67 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_0
%69 = OpCompositeExtract %v3float %67 0
%70 = OpCompositeExtract %v3float %67 2
%71 = OpCompositeExtract %float %67 1
%72 = OpCompositeExtract %float %67 3
%73 = OpLoad %56 %tlas
OpTraceRayKHR %73 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %69 %71 %70 %72 %p
%ray_payload_1 = OpLoad %RayPayload %p
OpStore %39 %76
OpStore %44 %45
%80 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_1
%82 = OpCompositeExtract %v3float %80 0
%83 = OpCompositeExtract %v3float %80 2
%84 = OpCompositeExtract %float %80 1
%85 = OpCompositeExtract %float %80 3
%86 = OpLoad %56 %tlas
OpTraceRayKHR %86 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %82 %84 %83 %85 %p
%ray_payload_2 = OpLoad %RayPayload %p
OpStore %39 %76
OpStore %44 %64
%91 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_2
%93 = OpCompositeExtract %v3float %91 0
%94 = OpCompositeExtract %v3float %91 2
%95 = OpCompositeExtract %float %91 1
%96 = OpCompositeExtract %float %91 3
%97 = OpLoad %56 %tlas
OpTraceRayKHR %97 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %93 %95 %94 %96 %p
%ray_payload_3 = OpLoad %RayPayload %p
OpStore %39 %100
OpStore %44 %45
%103 = OpLoad %RayDesc %ray
OpStore %p %ray_payload_3
%105 = OpCompositeExtract %v3float %103 0
%106 = OpCompositeExtract %v3float %103 2
%107 = OpCompositeExtract %float %103 1
%108 = OpCompositeExtract %float %103 3
%109 = OpLoad %56 %tlas
OpTraceRayKHR %109 %uint_0 %uint_255 %uint_0 %uint_0 %uint_0 %105 %107 %106 %108 %p
OpReturn
OpFunctionEnd
; Function missShader
%missShader = OpFunction %void None %3
%113 = OpLabel
%114 = OpExtInst %void %11 1 %115
%116 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_1
%117 = OpAtomicIAdd %uint %116 %uint_1 %uint_0 %uint_1
%121 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %119 %int_0
OpStore %121 %122
OpReturn
OpFunctionEnd
; Function closestHitShader
%closestHitShader = OpFunction %void None %3
%129 = OpLabel
%130 = OpExtInst %void %11 1 %131
%132 = OpAccessChain %_ptr_StorageBuffer_uint %debug_buffer %int_0 %int_2
%133 = OpAtomicIAdd %uint %132 %uint_1 %uint_0 %uint_1
%139 = OpAccessChain %_ptr_HitAttributeKHR_v2float %137 %int_0
%140 = OpLoad %v2float %139
%141 = OpCompositeExtract %float %140 0
%142 = OpFSub %float %float_1 %141
%143 = OpLoad %v2float %139
%144 = OpCompositeExtract %float %143 1
%145 = OpFSub %float %142 %144
%barycentric_coords = OpCompositeConstruct %v3float %145 %141 %144
%148 = OpAccessChain %_ptr_IncomingRayPayloadKHR_v3float %147 %int_0
OpStore %148 %barycentric_coords
OpReturn
OpFunctionEnd
)asm";
return ray_tracing_pipeline_spv;
}
TEST_F(NegativeDebugPrintfRayTracing, Raygen) {
TEST_DESCRIPTION("Test debug printf in raygen shader.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitDebugPrintfFramework());
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_debug_printf : enable
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
layout(location = 0) rayPayloadEXT vec3 hit;
void main() {
debugPrintfEXT("In Raygen\n");
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();
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_errorMonitor->SetDesiredInfo("In Raygen");
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDebugPrintfRayTracing, RaygenOneMissShaderOneClosestHitShader) {
TEST_DESCRIPTION("Test debug printf in raygen, miss and closest hit shaders.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitFrameworkWithPrintfBufferSize(1024 * 1024));
RETURN_IF_SKIP(InitState());
// #ARNO_TODO: For clarity, here geometry should be set explicitly, as of now the ray hitting or not
// implicitly depends on the default triangle position.
auto blas = std::make_shared<vkt::as::BuildGeometryInfoKHR>(
vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::Triangle));
// Build Bottom Level Acceleration Structure
m_command_buffer.Begin();
blas->BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
// Build Top Level Acceleration Structure
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, blas);
m_command_buffer.Begin();
tlas.BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
// Buffer used to count invocations for the 3 shader types
vkt::Buffer debug_buffer(*m_device, 3 * 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.handle(), debug_buffer.handle(), 0, debug_buffer.CreateInfo().size, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
vkt::rt::Pipeline pipeline(*this, m_device);
const char* ray_gen = R"glsl(
#version 460
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_debug_printf : enable
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
layout(binding = 1, set = 0) buffer DbgBuffer {
uint debug_buffer[];
};
layout(location = 0) rayPayloadEXT vec3 hit;
void main() {
uint last = atomicAdd(debug_buffer[0], 1);
debugPrintfEXT("In Raygen %u", last);
vec3 ray_origin = vec3(0,0,-50);
vec3 ray_direction = vec3(0,0,1);
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0);
// Will miss
ray_origin = vec3(0,0,-50);
ray_direction = vec3(0,0,-1);
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0);
// Will miss
ray_origin = vec3(0,0,50);
ray_direction = vec3(0,0,1);
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0);
ray_origin = vec3(0,0,50);
ray_direction = vec3(0,0,-1);
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0);
// Will miss
ray_origin = vec3(0,0,0);
ray_direction = vec3(0,0,1);
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, ray_origin, 0.01, ray_direction, 1000.0, 0);
}
)glsl";
pipeline.SetGlslRayGenShader(ray_gen);
const char* miss = R"glsl(
#version 460
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_debug_printf : enable
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
layout(binding = 1, set = 0) buffer DbgBuffer {
uint debug_buffer[];
};
layout(location = 0) rayPayloadInEXT vec3 hit;
void main() {
uint last = atomicAdd(debug_buffer[1], 1);
debugPrintfEXT("In Miss %u", last);
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
#extension GL_EXT_debug_printf : enable
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
layout(binding = 1, set = 0) buffer DbgBuffer {
uint debug_buffer[];
};
layout(location = 0) rayPayloadInEXT vec3 hit;
hitAttributeEXT vec2 baryCoord;
void main() {
uint last = atomicAdd(debug_buffer[2], 1);
debugPrintfEXT("In Closest Hit %u", last);
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_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer.handle(), 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
pipeline.Build();
constexpr uint32_t frames_count = 14;
const uint32_t ray_gen_width = 1;
const uint32_t ray_gen_height = 4;
const uint32_t ray_gen_depth = 1;
const uint32_t ray_gen_rays_count = ray_gen_width * ray_gen_height * ray_gen_depth;
for (uint32_t frame = 0; frame < frames_count; ++frame) {
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(),
0, 1, &pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt();
vk::CmdTraceRaysKHR(m_command_buffer.handle(), &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt,
&trace_rays_sbt.hit_sbt, &trace_rays_sbt.callable_sbt, ray_gen_width, ray_gen_height, ray_gen_depth);
m_command_buffer.End();
for (uint32_t i = 0; i < ray_gen_rays_count; ++i) {
std::string msg = "In Raygen " + std::to_string(frame * ray_gen_rays_count + i);
m_errorMonitor->SetDesiredInfo(msg.c_str());
}
for (uint32_t i = 0; i < 3 * ray_gen_rays_count; ++i) {
std::string msg = "In Miss " + std::to_string(frame * 3 * ray_gen_rays_count + i);
m_errorMonitor->SetDesiredInfo(msg.c_str());
}
for (uint32_t i = 0; i < 2 * ray_gen_rays_count; ++i) {
std::string msg = "In Closest Hit " + std::to_string(frame * 2 * ray_gen_rays_count + i);
m_errorMonitor->SetDesiredInfo(msg.c_str());
}
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
m_errorMonitor->VerifyFound();
}
auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map());
ASSERT_EQ(debug_buffer_ptr[0], ray_gen_rays_count * frames_count);
ASSERT_EQ(debug_buffer_ptr[1], 3 * ray_gen_rays_count * frames_count);
ASSERT_EQ(debug_buffer_ptr[2], 2 * ray_gen_rays_count * frames_count);
debug_buffer.Memory().Unmap();
}
TEST_F(NegativeDebugPrintfRayTracing, OneMultiEntryPointsShader) {
TEST_DESCRIPTION(
"Test debug printf in a multi entry points shader. 1 ray generation shader, 1 miss shader, 1 closest hit shader");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitDebugPrintfFramework());
RETURN_IF_SKIP(InitState());
// #ARNO_TODO: For clarity, here geometry should be set explicitly, as of now the ray hitting or not
// implicitly depends on the default triangle position.
auto blas = std::make_shared<vkt::as::BuildGeometryInfoKHR>(
vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device, vkt::as::GeometryKHR::Type::Triangle));
// Build Bottom Level Acceleration Structure
m_command_buffer.Begin();
blas->BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
// Build Top Level Acceleration Structure
vkt::as::BuildGeometryInfoKHR tlas = vkt::as::blueprint::BuildGeometryInfoSimpleOnDeviceTopLevel(*m_device, blas);
m_command_buffer.Begin();
tlas.BuildCmdBuffer(m_command_buffer.handle());
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
// Buffer used to count invocations for the 3 shader types
vkt::Buffer debug_buffer(*m_device, 3 * 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.handle(), debug_buffer.handle(), 0, debug_buffer.CreateInfo().size, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
vkt::rt::Pipeline pipeline(*this, m_device);
pipeline.AddSpirvRayGenShader(GetSlangShader2(), "main");
pipeline.AddSpirvMissShader(GetSlangShader2(), "main");
pipeline.AddSpirvClosestHitShader(GetSlangShader2(), "main");
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer.handle(), 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
pipeline.Build();
uint32_t frames_count = 42;
for (uint32_t frame = 0; frame < frames_count; ++frame) {
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(),
0, 1, &pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt();
vk::CmdTraceRaysKHR(m_command_buffer.handle(), &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->SetDesiredInfo("In Raygen");
m_errorMonitor->SetDesiredInfo("In Miss", 3);
m_errorMonitor->SetDesiredInfo("In Closest Hit", 2);
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
}
m_errorMonitor->VerifyFound();
auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map());
ASSERT_EQ(debug_buffer_ptr[0], frames_count);
ASSERT_EQ(debug_buffer_ptr[1], 3 * frames_count);
ASSERT_EQ(debug_buffer_ptr[2], 2 * frames_count);
debug_buffer.Memory().Unmap();
}
TEST_F(NegativeDebugPrintfRayTracing, OneMultiEntryPointsShader2CmdTraceRays) {
TEST_DESCRIPTION(
"Test debug printf in a multi entry points shader. 2 ray generation shaders, 2 miss shaders, 2 closest hit shaders."
"Trace rays using vkCmdTraceRaysKHR");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(InitDebugPrintfFramework());
RETURN_IF_SKIP(InitState());
std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas;
vkt::as::BuildGeometryInfoKHR tlas = GetCubesTLAS(cube_blas);
// Buffer used to count invocations for the 2 * 3 shaders
vkt::Buffer debug_buffer(*m_device, 2 * 3 * 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.handle(), debug_buffer.handle(), 0, debug_buffer.CreateInfo().size, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
vkt::rt::Pipeline pipeline(*this, m_device);
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader");
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader2");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader2");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader2");
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer.handle(), 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
pipeline.Build();
uint32_t frames_count = 42;
for (uint32_t frame = 0; frame < frames_count; ++frame) {
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(),
0, 1, &pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
// Invoke ray gen shader 1
vkt::rt::TraceRaysSbt sbt_ray_gen_1 = pipeline.GetTraceRaysSbt(0);
vk::CmdTraceRaysKHR(m_command_buffer.handle(), &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);
// Invoke ray gen shader 2
vkt::rt::TraceRaysSbt sbt_ray_gen_2 = pipeline.GetTraceRaysSbt(1);
vk::CmdTraceRaysKHR(m_command_buffer.handle(), &sbt_ray_gen_2.ray_gen_sbt, &sbt_ray_gen_2.miss_sbt, &sbt_ray_gen_2.hit_sbt,
&sbt_ray_gen_2.callable_sbt, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredInfo("In Raygen 1");
m_errorMonitor->SetDesiredInfo("In Raygen 2");
m_errorMonitor->SetDesiredInfo("In Miss 1", 2);
m_errorMonitor->SetDesiredInfo("In Miss 2", 2);
m_errorMonitor->SetDesiredInfo("In Closest Hit 1", 2);
m_errorMonitor->SetDesiredInfo("In Closest Hit 2", 3);
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
}
m_errorMonitor->VerifyFound();
// Check debug buffer to cross check that every expected shader invocation happened
auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map());
ASSERT_EQ(debug_buffer_ptr[0], 1 * frames_count);
ASSERT_EQ(debug_buffer_ptr[1], 1 * frames_count);
ASSERT_EQ(debug_buffer_ptr[2], (2 + 0) * frames_count);
ASSERT_EQ(debug_buffer_ptr[3], (1 + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[4], (1 + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[5], (1 + 2) * frames_count);
debug_buffer.Memory().Unmap();
}
TEST_F(NegativeDebugPrintfRayTracing, OneMultiEntryPointsShader2CmdTraceRaysIndirect) {
TEST_DESCRIPTION(
"Test debug printf in a multi entry points shader. 2 ray generation shaders, 2 miss shaders, 2 closest hit shaders."
"Trace rays using vkCmdTraceRaysIndirect2KHR");
SetTargetApiVersion(VK_API_VERSION_1_2);
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::rayTracingPipelineTraceRaysIndirect2);
RETURN_IF_SKIP(InitDebugPrintfFramework());
RETURN_IF_SKIP(InitState());
std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas;
vkt::as::BuildGeometryInfoKHR tlas = GetCubesTLAS(cube_blas);
// Buffer used to count invocations for the 2 * 3 shaders
vkt::Buffer debug_buffer(*m_device, 2 * 3 * 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.handle(), debug_buffer.handle(), 0, debug_buffer.CreateInfo().size, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
vkt::rt::Pipeline pipeline(*this, m_device);
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader");
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader2");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader2");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader2");
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer.handle(), 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
pipeline.Build();
vkt::Buffer sbt_ray_gen_1 = pipeline.GetTraceRaysSbtIndirectBuffer(0, 1, 1, 1);
vkt::Buffer sbt_ray_gen_2 = pipeline.GetTraceRaysSbtIndirectBuffer(1, 1, 1, 1);
uint32_t frames_count = 42;
for (uint32_t frame = 0; frame < frames_count; ++frame) {
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(),
0, 1, &pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
// Invoke ray gen shader 1
vk::CmdTraceRaysIndirect2KHR(m_command_buffer.handle(), sbt_ray_gen_1.Address());
// Invoke ray gen shader 2
vk::CmdTraceRaysIndirect2KHR(m_command_buffer.handle(), sbt_ray_gen_2.Address());
m_command_buffer.End();
m_errorMonitor->SetDesiredInfo("In Raygen 1");
m_errorMonitor->SetDesiredInfo("In Raygen 2");
m_errorMonitor->SetDesiredInfo("In Miss 1", 2);
m_errorMonitor->SetDesiredInfo("In Miss 2", 2);
m_errorMonitor->SetDesiredInfo("In Closest Hit 1", 2);
m_errorMonitor->SetDesiredInfo("In Closest Hit 2", 3);
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
m_errorMonitor->VerifyFound();
}
// Check debug buffer to cross check that every expected shader invocation happened
auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map());
ASSERT_EQ(debug_buffer_ptr[0], 1 * frames_count);
ASSERT_EQ(debug_buffer_ptr[1], 1 * frames_count);
ASSERT_EQ(debug_buffer_ptr[2], (2 + 0) * frames_count);
ASSERT_EQ(debug_buffer_ptr[3], (1 + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[4], (1 + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[5], (1 + 2) * frames_count);
debug_buffer.Memory().Unmap();
}
TEST_F(NegativeDebugPrintfRayTracing, OneMultiEntryPointsShader2CmdTraceRaysIndirectDeferredBuild) {
TEST_DESCRIPTION(
"Test debug printf in a multi entry points shader. 2 ray generation shaders, 2 miss shaders, 2 closest hit shaders."
"Trace rays using vkCmdTraceRaysIndirect2KHR");
SetTargetApiVersion(VK_API_VERSION_1_2);
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::rayTracingPipelineTraceRaysIndirect2);
RETURN_IF_SKIP(InitFrameworkWithPrintfBufferSize(1024 * 1024));
RETURN_IF_SKIP(InitState());
std::shared_ptr<vkt::as::BuildGeometryInfoKHR> cube_blas;
vkt::as::BuildGeometryInfoKHR tlas = GetCubesTLAS(cube_blas);
// Buffer used to count invocations for the 2 * 3 shaders
vkt::Buffer debug_buffer(*m_device, 2 * 3 * 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.handle(), debug_buffer.handle(), 0, debug_buffer.CreateInfo().size, 0);
m_command_buffer.End();
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
vkt::rt::Pipeline pipeline(*this, m_device);
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader");
pipeline.AddSpirvRayGenShader(GetSlangShader1(), "rayGenShader2");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader");
pipeline.AddSpirvMissShader(GetSlangShader1(), "missShader2");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader");
pipeline.AddSpirvClosestHitShader(GetSlangShader1(), "closestHitShader2");
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, debug_buffer.handle(), 0, VK_WHOLE_SIZE,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
pipeline.DeferBuild();
pipeline.Build();
const uint32_t ray_gen_1_width = 2;
const uint32_t ray_gen_1_height = 2;
const uint32_t ray_gen_1_depth = 1;
const uint32_t ray_gen_1_rays_count = ray_gen_1_width * ray_gen_1_height * ray_gen_1_depth;
vkt::Buffer sbt_ray_gen_1 = pipeline.GetTraceRaysSbtIndirectBuffer(0, ray_gen_1_width, ray_gen_1_height, ray_gen_1_depth);
vkt::Buffer sbt_ray_gen_2 = pipeline.GetTraceRaysSbtIndirectBuffer(1, 1, 1, 1);
uint32_t frames_count = 1;
for (uint32_t frame = 0; frame < frames_count; ++frame) {
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(),
0, 1, &pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.Handle());
// Invoke ray gen shader 1
vk::CmdTraceRaysIndirect2KHR(m_command_buffer.handle(), sbt_ray_gen_1.Address());
// Invoke ray gen shader 2
vk::CmdTraceRaysIndirect2KHR(m_command_buffer.handle(), sbt_ray_gen_2.Address());
m_command_buffer.End();
m_errorMonitor->SetDesiredInfo("In Raygen 1", ray_gen_1_rays_count);
m_errorMonitor->SetDesiredInfo("In Raygen 2");
m_errorMonitor->SetDesiredInfo("In Miss 1", 2 * ray_gen_1_rays_count + 0);
m_errorMonitor->SetDesiredInfo("In Miss 2", 1 * ray_gen_1_rays_count + 1);
m_errorMonitor->SetDesiredInfo("In Closest Hit 1", 1 * ray_gen_1_rays_count + 1);
m_errorMonitor->SetDesiredInfo("In Closest Hit 2", 1 * ray_gen_1_rays_count + 2);
m_default_queue->Submit(m_command_buffer);
m_default_queue->Wait();
}
m_errorMonitor->VerifyFound();
// Check debug buffer to cross check that every expected shader invocation happened
auto debug_buffer_ptr = static_cast<uint32_t*>(debug_buffer.Memory().Map());
ASSERT_EQ(debug_buffer_ptr[0], 1 * ray_gen_1_rays_count * frames_count);
ASSERT_EQ(debug_buffer_ptr[1], 1 * frames_count);
ASSERT_EQ(debug_buffer_ptr[2], (2 * ray_gen_1_rays_count + 0) * frames_count);
ASSERT_EQ(debug_buffer_ptr[3], (1 * ray_gen_1_rays_count + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[4], (1 * ray_gen_1_rays_count + 1) * frames_count);
ASSERT_EQ(debug_buffer_ptr[5], (1 * ray_gen_1_rays_count + 2) * frames_count);
debug_buffer.Memory().Unmap();
}