diff options
author | Spencer Fricke <spencerfricke@gmail.com> | 2022-07-07 20:03:52 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-07 20:03:52 +0300 |
commit | bc5c8760af8375a0e92ee3318bda15ed9a165ef1 (patch) | |
tree | 8f6e7ae20d656ce70717c7943370c424b01aa2ab | |
parent | 05de650371360b33632ac6e4478869920e556748 (diff) |
spirv-val: Add Vulkan decoration interface (#4831)
-rw-r--r-- | source/val/validate_decorations.cpp | 50 | ||||
-rw-r--r-- | source/val/validation_state.cpp | 8 | ||||
-rw-r--r-- | test/val/val_builtins_test.cpp | 5 | ||||
-rw-r--r-- | test/val/val_decoration_test.cpp | 286 | ||||
-rw-r--r-- | test/val/val_interfaces_test.cpp | 2 |
5 files changed, 350 insertions, 1 deletions
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 907c18480..986f32953 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -811,6 +811,56 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { ++num_workgroup_variables_with_aliased; } } + + if (spvIsVulkanEnv(vstate.context()->target_env)) { + const auto* models = vstate.GetExecutionModels(entry_point); + const bool has_frag = + models->find(SpvExecutionModelFragment) != models->end(); + const bool has_vert = + models->find(SpvExecutionModelVertex) != models->end(); + for (const auto& decoration : + vstate.id_decorations(var_instr->id())) { + if (decoration == SpvDecorationFlat || + decoration == SpvDecorationNoPerspective || + decoration == SpvDecorationSample || + decoration == SpvDecorationCentroid) { + // VUID 04670 already validates these decorations are input/output + if (storage_class == SpvStorageClassInput && + (models->size() > 1 || has_vert)) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << vstate.VkErrorID(6202) + << "OpEntryPoint interfaces variable must not be vertex " + "execution model with an input storage class for " + "Entry Point id " + << entry_point << "."; + } else if (storage_class == SpvStorageClassOutput && + (models->size() > 1 || has_frag)) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << vstate.VkErrorID(6201) + << "OpEntryPoint interfaces variable must not be " + "fragment " + "execution model with an output storage class for " + "Entry Point id " + << entry_point << "."; + } + } + } + + const bool has_flat = + hasDecoration(var_instr->id(), SpvDecorationFlat, vstate); + if (has_frag && storage_class == SpvStorageClassInput && !has_flat && + ((vstate.IsFloatScalarType(type_id) && + vstate.GetBitWidth(type_id) == 64) || + vstate.IsIntScalarOrVectorType(type_id))) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << vstate.VkErrorID(4744) + << "Fragment OpEntryPoint operand " + << interface << " with Input interfaces with integer or " + "float type must have a Flat decoration " + "for Entry Point id " + << entry_point << "."; + } + } } if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1) { return vstate.diag(SPV_ERROR_INVALID_BINARY, diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 1b41f1efa..811f92aee 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1878,7 +1878,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id, case 4677: return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); case 4680: - return VUID_WRAP( VUID-StandaloneSpirv-OpTypeRuntimeArray-04680); + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeRuntimeArray-04680); case 4682: return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682); case 6426: @@ -1903,6 +1903,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733); case 4734: return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734); + case 4744: + return VUID_WRAP(VUID-StandaloneSpirv-Flat-04744); case 4777: return VUID_WRAP(VUID-StandaloneSpirv-OpImage-04777); case 4780: @@ -1919,6 +1921,10 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Location-04918); case 4919: return VUID_WRAP(VUID-StandaloneSpirv-Location-04919); + case 6201: + return VUID_WRAP(VUID-StandaloneSpirv-Flat-06201); + case 6202: + return VUID_WRAP(VUID-StandaloneSpirv-Flat-06202); case 6214: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214); case 6491: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index b76c16354..2cbe9a8ae 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -394,6 +394,11 @@ CodeGenerator GetVariableCodeGenerator(const char* const built_in, generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; + if ((0 == std::strcmp(storage_class, "Input")) && + (0 == std::strcmp(execution_model, "Fragment"))) { + // ensure any needed input types that might require Flat + generator.before_types_ += "OpDecorate %built_in_var Flat\n"; + } std::ostringstream after_types; if (InitializerRequired(storage_class)) { diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 1af45dd11..e117e6f8c 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -42,6 +42,7 @@ struct TestResult { }; using ValidateDecorations = spvtest::ValidateBase<bool>; +using ValidateDecorationString = spvtest::ValidateBase<std::string>; using ValidateVulkanCombineDecorationResult = spvtest::ValidateBase<std::tuple<const char*, const char*, TestResult>>; @@ -8409,6 +8410,291 @@ TEST_F(ValidateDecorations, RelaxedPrecisionDecorationOnStructMember) { EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); } +TEST_F(ValidateDecorations, VulkanFlatMultipleInterfaceGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability Geometry + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %layer %gl_Layer + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %layer Location 0 + OpDecorate %gl_Layer Flat + OpDecorate %gl_Layer BuiltIn Layer + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Output_int = OpTypePointer Output %int + %layer = OpVariable %_ptr_Output_int Output +%_ptr_Input_int = OpTypePointer Input %int + %gl_Layer = OpVariable %_ptr_Input_int Input + %main = OpFunction %void None %3 + %5 = OpLabel + %11 = OpLoad %int %gl_Layer + OpStore %layer %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanFlatMultipleInterfaceBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability Geometry + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %layer %gl_Layer + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %layer Location 0 + OpDecorate %gl_Layer BuiltIn Layer + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Output_int = OpTypePointer Output %int + %layer = OpVariable %_ptr_Output_int Output +%_ptr_Input_int = OpTypePointer Input %int + %gl_Layer = OpVariable %_ptr_Input_int Input + %main = OpFunction %void None %3 + %5 = OpLabel + %11 = OpLoad %int %gl_Layer + OpStore %layer %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Flat-04744")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Fragment OpEntryPoint operand 4 with Input interfaces with integer " + "or float type must have a Flat decoration for Entry Point id 2.")); +} + +TEST_F(ValidateDecorations, VulkanNoFlatFloat32) { + std::string spirv = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %in Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Input_float = OpTypePointer Input %float + %in = OpVariable %_ptr_Input_float Input + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_float Function + %11 = OpLoad %float %in + OpStore %b %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanNoFlatFloat64) { + std::string spirv = R"( + OpCapability Shader + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %in Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %double = OpTypeFloat 64 +%_ptr_Function_double = OpTypePointer Function %double +%_ptr_Input_double = OpTypePointer Input %double + %in = OpVariable %_ptr_Input_double Input + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_double Function + %11 = OpLoad %double %in + OpStore %b %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Flat-04744")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Fragment OpEntryPoint operand 3 with Input interfaces with integer " + "or float type must have a Flat decoration for Entry Point id 2.")); +} + +TEST_F(ValidateDecorations, VulkanNoFlatVectorFloat64) { + std::string spirv = R"( + OpCapability Shader + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %in Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %double = OpTypeFloat 64 + %v2double = OpTypeVector %double 2 +%_ptr_Function_v2double = OpTypePointer Function %v2double +%_ptr_Input_v2double = OpTypePointer Input %v2double + %in = OpVariable %_ptr_Input_v2double Input + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_v2double Function + %11 = OpLoad %v2double %in + OpStore %b %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanNoFlatIntVector) { + std::string spirv = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %in Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v2int = OpTypeVector %int 2 +%_ptr_Function_v2int = OpTypePointer Function %v2int +%_ptr_Input_v2int = OpTypePointer Input %v2int + %in = OpVariable %_ptr_Input_v2int Input + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_v2int Function + %12 = OpLoad %v2int %in + OpStore %b %12 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Flat-04744")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Fragment OpEntryPoint operand 3 with Input interfaces with integer " + "or float type must have a Flat decoration for Entry Point id 2.")); +} + +TEST_P(ValidateDecorationString, VulkanOutputInvalidInterface) { + const std::string decoration = GetParam(); + std::stringstream ss; + ss << R"( + OpCapability Shader + OpCapability SampleRateShading + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %out + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpDecorate %out )" + << decoration << R"( + OpDecorate %out Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Output_int = OpTypePointer Output %int + %out = OpVariable %_ptr_Output_int Output + %int_1 = OpConstant %int 1 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %out %int_1 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(ss.str(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Flat-06201")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpEntryPoint interfaces variable must not be fragment execution " + "model with an output storage class for Entry Point id 2.")); +} + +TEST_P(ValidateDecorationString, VulkanVertexInputInvalidInterface) { + const std::string decoration = GetParam(); + std::stringstream ss; + ss << R"( + OpCapability Shader + OpCapability SampleRateShading + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %out %in + OpSource GLSL 450 + OpDecorate %in )" + << decoration << R"( + OpDecorate %out Location 0 + OpDecorate %in Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Output_int = OpTypePointer Output %int + %out = OpVariable %_ptr_Output_int Output +%_ptr_Input_int = OpTypePointer Input %int + %in = OpVariable %_ptr_Input_int Input + %main = OpFunction %void None %3 + %5 = OpLabel + %11 = OpLoad %int %in + OpStore %out %11 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(ss.str(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Flat-06202")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpEntryPoint interfaces variable must not be vertex execution " + "model with an input storage class for Entry Point id 2.")); +} + +INSTANTIATE_TEST_SUITE_P(FragmentInputInterface, ValidateDecorationString, + ::testing::Values("Flat", "NoPerspective", "Sample", + "Centroid")); + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index bec8d0267..d9c3748f1 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -711,7 +711,9 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %var1 %var2 OpExecutionMode %main OriginUpperLeft OpDecorate %var1 Location 0 +OpDecorate %var1 Flat OpDecorate %var2 Location 1 +OpDecorate %var2 Flat %void = OpTypeVoid %void_fn = OpTypeFunction %void %float = OpTypeFloat 32 |