// Copyright (c) 2022 The Khronos Group 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. // Tests ray query instructions from SPV_KHR_ray_query. #include #include #include "gmock/gmock.h" #include "spirv-tools/libspirv.h" #include "test/val/val_fixtures.h" namespace spvtools { namespace val { namespace { using ::testing::HasSubstr; using ::testing::Values; using ValidateRayQuery = spvtest::ValidateBase; std::string GenerateShaderCode( const std::string& body, const std::string& capabilities_and_extensions = "", const std::string& declarations = "") { std::ostringstream ss; ss << R"( OpCapability Shader OpCapability Int64 OpCapability Float64 OpCapability RayQueryKHR OpExtension "SPV_KHR_ray_query" )"; ss << capabilities_and_extensions; ss << R"( OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %main "main" OpExecutionMode %main LocalSize 1 1 1 OpDecorate %top_level_as DescriptorSet 0 OpDecorate %top_level_as Binding 0 %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool %f32 = OpTypeFloat 32 %f64 = OpTypeFloat 64 %u32 = OpTypeInt 32 0 %s32 = OpTypeInt 32 1 %u64 = OpTypeInt 64 0 %s64 = OpTypeInt 64 1 %type_rq = OpTypeRayQueryKHR %type_as = OpTypeAccelerationStructureKHR %s32vec2 = OpTypeVector %s32 2 %u32vec2 = OpTypeVector %u32 2 %f32vec2 = OpTypeVector %f32 2 %u32vec3 = OpTypeVector %u32 3 %s32vec3 = OpTypeVector %s32 3 %f32vec3 = OpTypeVector %f32 3 %u32vec4 = OpTypeVector %u32 4 %s32vec4 = OpTypeVector %s32 4 %f32vec4 = OpTypeVector %f32 4 %mat4x3 = OpTypeMatrix %f32vec3 4 %f32_0 = OpConstant %f32 0 %f64_0 = OpConstant %f64 0 %s32_0 = OpConstant %s32 0 %u32_0 = OpConstant %u32 0 %u64_0 = OpConstant %u64 0 %u32vec3_0 = OpConstantComposite %u32vec3 %u32_0 %u32_0 %u32_0 %f32vec3_0 = OpConstantComposite %f32vec3 %f32_0 %f32_0 %f32_0 %f32vec4_0 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0 %ptr_rq = OpTypePointer Private %type_rq %ray_query = OpVariable %ptr_rq Private %ptr_as = OpTypePointer UniformConstant %type_as %top_level_as = OpVariable %ptr_as UniformConstant %ptr_function_u32 = OpTypePointer Function %u32 %ptr_function_f32 = OpTypePointer Function %f32 %ptr_function_f32vec3 = OpTypePointer Function %f32vec3 )"; ss << declarations; ss << R"( %main = OpFunction %void None %func %main_entry = OpLabel )"; ss << body; ss << R"( OpReturn OpFunctionEnd)"; return ss.str(); } std::string RayQueryResult(std::string opcode) { if (opcode.compare("OpRayQueryProceedKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionTypeKHR") == 0 || opcode.compare("OpRayQueryGetRayTMinKHR") == 0 || opcode.compare("OpRayQueryGetRayFlagsKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionTKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceCustomIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceIdKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceShaderBindingTableRecord" "OffsetKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionGeometryIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionPrimitiveIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionBarycentricsKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionFrontFaceKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionCandidateAABBOpaqueKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectRayDirectionKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectRayOriginKHR") == 0 || opcode.compare("OpRayQueryGetWorldRayDirectionKHR") == 0 || opcode.compare("OpRayQueryGetWorldRayOriginKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectToWorldKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionWorldToObjectKHR") == 0) { return "%result ="; } return ""; } std::string RayQueryResultType(std::string opcode, bool valid) { if (opcode.compare("OpRayQueryGetIntersectionTypeKHR") == 0 || opcode.compare("OpRayQueryGetRayFlagsKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceCustomIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceIdKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceShaderBindingTableRecord" "OffsetKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionGeometryIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionPrimitiveIndexKHR") == 0) { return valid ? "%u32" : "%f64"; } if (opcode.compare("OpRayQueryGetRayTMinKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionTKHR") == 0) { return valid ? "%f32" : "%f64"; } if (opcode.compare("OpRayQueryGetIntersectionBarycentricsKHR") == 0) { return valid ? "%f32vec2" : "%f64"; } if (opcode.compare("OpRayQueryGetIntersectionObjectRayDirectionKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectRayOriginKHR") == 0 || opcode.compare("OpRayQueryGetWorldRayDirectionKHR") == 0 || opcode.compare("OpRayQueryGetWorldRayOriginKHR") == 0) { return valid ? "%f32vec3" : "%f64"; } if (opcode.compare("OpRayQueryProceedKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionFrontFaceKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionCandidateAABBOpaqueKHR") == 0) { return valid ? "%bool" : "%f64"; } if (opcode.compare("OpRayQueryGetIntersectionObjectToWorldKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionWorldToObjectKHR") == 0) { return valid ? "%mat4x3" : "%f64"; } return ""; } std::string RayQueryIntersection(std::string opcode, bool valid) { if (opcode.compare("OpRayQueryGetIntersectionTypeKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionTKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceCustomIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceIdKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionInstanceShaderBindingTableRecord" "OffsetKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionGeometryIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionPrimitiveIndexKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionBarycentricsKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionFrontFaceKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectRayDirectionKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectRayOriginKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionObjectToWorldKHR") == 0 || opcode.compare("OpRayQueryGetIntersectionWorldToObjectKHR") == 0) { return valid ? "%s32_0" : "%f32_0"; } return ""; } using RayQueryCommon = spvtest::ValidateBase; TEST_P(RayQueryCommon, Success) { std::string opcode = GetParam(); std::ostringstream ss; ss << RayQueryResult(opcode); ss << " " << opcode << " "; ss << RayQueryResultType(opcode, true); ss << " %ray_query "; ss << RayQueryIntersection(opcode, true); CompileSuccessfully(GenerateShaderCode(ss.str()).c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_P(RayQueryCommon, BadQuery) { std::string opcode = GetParam(); std::ostringstream ss; ss << RayQueryResult(opcode); ss << " " << opcode << " "; ss << RayQueryResultType(opcode, true); ss << " %top_level_as "; ss << RayQueryIntersection(opcode, true); CompileSuccessfully(GenerateShaderCode(ss.str()).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray Query must be a pointer to OpTypeRayQueryKHR")); } TEST_P(RayQueryCommon, BadResult) { std::string opcode = GetParam(); std::string result_type = RayQueryResultType(opcode, false); if (!result_type.empty()) { std::ostringstream ss; ss << RayQueryResult(opcode); ss << " " << opcode << " "; ss << result_type; ss << " %ray_query "; ss << RayQueryIntersection(opcode, true); CompileSuccessfully(GenerateShaderCode(ss.str()).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); std::string correct_result_type = RayQueryResultType(opcode, true); if (correct_result_type.compare("%u32") == 0) { EXPECT_THAT( getDiagnosticString(), HasSubstr("expected Result Type to be 32-bit int scalar type")); } else if (correct_result_type.compare("%f32") == 0) { EXPECT_THAT( getDiagnosticString(), HasSubstr("expected Result Type to be 32-bit float scalar type")); } else if (correct_result_type.compare("%f32vec2") == 0) { EXPECT_THAT(getDiagnosticString(), HasSubstr("expected Result Type to be 32-bit float " "2-component vector type")); } else if (correct_result_type.compare("%f32vec3") == 0) { EXPECT_THAT(getDiagnosticString(), HasSubstr("expected Result Type to be 32-bit float " "3-component vector type")); } else if (correct_result_type.compare("%bool") == 0) { EXPECT_THAT(getDiagnosticString(), HasSubstr("expected Result Type to be bool scalar type")); } else if (correct_result_type.compare("%mat4x3") == 0) { EXPECT_THAT(getDiagnosticString(), HasSubstr("expected matrix type as Result Type")); } } } TEST_P(RayQueryCommon, BadIntersection) { std::string opcode = GetParam(); std::string intersection = RayQueryIntersection(opcode, false); if (!intersection.empty()) { std::ostringstream ss; ss << RayQueryResult(opcode); ss << " " << opcode << " "; ss << RayQueryResultType(opcode, true); ss << " %ray_query "; ss << intersection; CompileSuccessfully(GenerateShaderCode(ss.str()).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr( "expected Intersection ID to be a constant 32-bit int scalar")); } } INSTANTIATE_TEST_SUITE_P( ValidateRayQueryCommon, RayQueryCommon, Values("OpRayQueryTerminateKHR", "OpRayQueryConfirmIntersectionKHR", "OpRayQueryProceedKHR", "OpRayQueryGetIntersectionTypeKHR", "OpRayQueryGetRayTMinKHR", "OpRayQueryGetRayFlagsKHR", "OpRayQueryGetWorldRayDirectionKHR", "OpRayQueryGetWorldRayOriginKHR", "OpRayQueryGetIntersectionTKHR", "OpRayQueryGetIntersectionInstanceCustomIndexKHR", "OpRayQueryGetIntersectionInstanceIdKHR", "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR", "OpRayQueryGetIntersectionGeometryIndexKHR", "OpRayQueryGetIntersectionPrimitiveIndexKHR", "OpRayQueryGetIntersectionBarycentricsKHR", "OpRayQueryGetIntersectionFrontFaceKHR", "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR", "OpRayQueryGetIntersectionObjectRayDirectionKHR", "OpRayQueryGetIntersectionObjectRayOriginKHR", "OpRayQueryGetIntersectionObjectToWorldKHR", "OpRayQueryGetIntersectionWorldToObjectKHR")); // tests various Intersection operand types TEST_F(ValidateRayQuery, IntersectionSuccess) { const std::string body = R"( %result_1 = OpRayQueryGetIntersectionFrontFaceKHR %bool %ray_query %s32_0 %result_2 = OpRayQueryGetIntersectionFrontFaceKHR %bool %ray_query %u32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateRayQuery, IntersectionVector) { const std::string body = R"( %result = OpRayQueryGetIntersectionFrontFaceKHR %bool %ray_query %u32vec3_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("expected Intersection ID to be a constant 32-bit int scalar")); } TEST_F(ValidateRayQuery, IntersectionNonConstantVariable) { const std::string body = R"( %var = OpVariable %ptr_function_u32 Function %result = OpRayQueryGetIntersectionFrontFaceKHR %bool %ray_query %var )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("expected Intersection ID to be a constant 32-bit int scalar")); } TEST_F(ValidateRayQuery, IntersectionNonConstantLoad) { const std::string body = R"( %var = OpVariable %ptr_function_u32 Function %load = OpLoad %u32 %var %result = OpRayQueryGetIntersectionFrontFaceKHR %bool %ray_query %load )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("expected Intersection ID to be a constant 32-bit int scalar")); } TEST_F(ValidateRayQuery, InitializeSuccess) { const std::string body = R"( %var_u32 = OpVariable %ptr_function_u32 Function %var_f32 = OpVariable %ptr_function_f32 Function %var_f32vec3 = OpVariable %ptr_function_f32vec3 Function %as = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %as %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 %_u32 = OpLoad %u32 %var_u32 %_f32 = OpLoad %f32 %var_f32 %_f32vec3 = OpLoad %f32vec3 %var_f32vec3 OpRayQueryInitializeKHR %ray_query %as %_u32 %_u32 %_f32vec3 %_f32 %_f32vec3 %_f32 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateRayQuery, InitializeFunctionSuccess) { const std::string declaration = R"( %rq_ptr = OpTypePointer Private %type_rq %rq_func_type = OpTypeFunction %void %rq_ptr %rq_var_1 = OpVariable %rq_ptr Private %rq_var_2 = OpVariable %rq_ptr Private )"; const std::string body = R"( %fcall_1 = OpFunctionCall %void %rq_func %rq_var_1 %as_1 = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %rq_var_1 %as_1 %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 %fcall_2 = OpFunctionCall %void %rq_func %rq_var_2 OpReturn OpFunctionEnd %rq_func = OpFunction %void None %rq_func_type %rq_param = OpFunctionParameter %rq_ptr %label = OpLabel %as_2 = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %rq_param %as_2 %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body, "", declaration).c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateRayQuery, InitializeBadRayQuery) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %top_level_as %load %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray Query must be a pointer to OpTypeRayQueryKHR")); } TEST_F(ValidateRayQuery, InitializeBadAS) { const std::string body = R"( OpRayQueryInitializeKHR %ray_query %ray_query %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Expected Acceleration Structure to be of type " "OpTypeAccelerationStructureKHR")); } TEST_F(ValidateRayQuery, InitializeBadRayFlags64) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u64_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray Flags must be a 32-bit int scalar")); } TEST_F(ValidateRayQuery, InitializeBadRayFlagsVector) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32vec2 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand '15[%v2uint]' cannot be a type")); } TEST_F(ValidateRayQuery, InitializeBadCullMask) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %f32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Cull Mask must be a 32-bit int scalar")); } TEST_F(ValidateRayQuery, InitializeBadRayOriginVec4) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %f32vec4_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("Ray Origin must be a 32-bit float 3-component vector")); } TEST_F(ValidateRayQuery, InitializeBadRayOriginFloat) { const std::string body = R"( %var_f32 = OpVariable %ptr_function_f32 Function %_f32 = OpLoad %f32 %var_f32 %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %_f32 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("Ray Origin must be a 32-bit float 3-component vector")); } TEST_F(ValidateRayQuery, InitializeBadRayOriginInt) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %u32vec3_0 %f32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("Ray Origin must be a 32-bit float 3-component vector")); } TEST_F(ValidateRayQuery, InitializeBadRayTMin) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %f32vec3_0 %u32_0 %f32vec3_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray TMin must be a 32-bit float scalar")); } TEST_F(ValidateRayQuery, InitializeBadRayDirection) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec4_0 %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("Ray Direction must be a 32-bit float 3-component vector")); } TEST_F(ValidateRayQuery, InitializeBadRayTMax) { const std::string body = R"( %load = OpLoad %type_as %top_level_as OpRayQueryInitializeKHR %ray_query %load %u32_0 %u32_0 %f32vec3_0 %f32_0 %f32vec3_0 %f64_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray TMax must be a 32-bit float scalar")); } TEST_F(ValidateRayQuery, GenerateIntersectionSuccess) { const std::string body = R"( %var = OpVariable %ptr_function_f32 Function %load = OpLoad %f32 %var OpRayQueryGenerateIntersectionKHR %ray_query %f32_0 OpRayQueryGenerateIntersectionKHR %ray_query %load )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateRayQuery, GenerateIntersectionBadRayQuery) { const std::string body = R"( OpRayQueryGenerateIntersectionKHR %top_level_as %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Ray Query must be a pointer to OpTypeRayQueryKHR")); } TEST_F(ValidateRayQuery, GenerateIntersectionBadHitT) { const std::string body = R"( OpRayQueryGenerateIntersectionKHR %ray_query %u32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Hit T must be a 32-bit float scalar")); } TEST_F(ValidateRayQuery, RayQueryArraySuccess) { // This shader is slightly different to the ones above, so it doesn't reuse // the shader code generator. const std::string shader = R"( OpCapability Shader OpCapability RayQueryKHR OpExtension "SPV_KHR_ray_query" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %main "main" OpExecutionMode %main LocalSize 1 1 1 OpSource GLSL 460 OpDecorate %topLevelAS DescriptorSet 0 OpDecorate %topLevelAS Binding 0 OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize %void = OpTypeVoid %func = OpTypeFunction %void %ray_query = OpTypeRayQueryKHR %uint = OpTypeInt 32 0 %uint_2 = OpConstant %uint 2 %ray_query_array = OpTypeArray %ray_query %uint_2 %ptr_ray_query_array = OpTypePointer Private %ray_query_array %rayQueries = OpVariable %ptr_ray_query_array Private %int = OpTypeInt 32 1 %int_0 = OpConstant %int 0 %ptr_ray_query = OpTypePointer Private %ray_query %accel_struct = OpTypeAccelerationStructureKHR %ptr_accel_struct = OpTypePointer UniformConstant %accel_struct %topLevelAS = OpVariable %ptr_accel_struct UniformConstant %uint_0 = OpConstant %uint 0 %uint_255 = OpConstant %uint 255 %float = OpTypeFloat 32 %v3float = OpTypeVector %float 3 %float_0 = OpConstant %float 0 %vec3_zero = OpConstantComposite %v3float %float_0 %float_0 %float_0 %float_1 = OpConstant %float 1 %vec3_xy_0_z_1 = OpConstantComposite %v3float %float_0 %float_0 %float_1 %float_10 = OpConstant %float 10 %v3uint = OpTypeVector %uint 3 %uint_1 = OpConstant %uint 1 %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 %main = OpFunction %void None %func %main_label = OpLabel %first_ray_query = OpAccessChain %ptr_ray_query %rayQueries %int_0 %topLevelAS_val = OpLoad %accel_struct %topLevelAS OpRayQueryInitializeKHR %first_ray_query %topLevelAS_val %uint_0 %uint_255 %vec3_zero %float_0 %vec3_xy_0_z_1 %float_10 OpReturn OpFunctionEnd )"; CompileSuccessfully(shader); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } } // namespace } // namespace val } // namespace spvtools