| // 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 <sstream> | |
| #include <string> | |
| #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<bool>; | |
| 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<std::string>; | |
| 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 |