From a1d38174b1f7d2651c718ae661886d606cb50a32 Mon Sep 17 00:00:00 2001 From: Tobski Date: Tue, 20 Oct 2020 13:00:13 +0100 Subject: [PATCH] Support SPV_KHR_fragment_shading_rate (#3943) --- include/spirv-tools/libspirv.h | 13 +-- source/operand.cpp | 3 + source/val/validate_builtins.cpp | 159 +++++++++++++++++++++++++++++++ test/val/val_builtins_test.cpp | 104 ++++++++++++++++++++ 4 files changed, 273 insertions(+), 6 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 16ea7ffac5..a0114c3f4b 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -176,12 +176,13 @@ typedef enum spv_operand_type_t { // Set 5: Operands that are a single word bitmask. // Sometimes a set bit indicates the instruction requires still more operands. - SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14 - SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15 - SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22 - SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23 - SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24 - SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26 + SPV_OPERAND_TYPE_IMAGE, // SPIR-V Sec 3.14 + SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, // SPIR-V Sec 3.15 + SPV_OPERAND_TYPE_SELECTION_CONTROL, // SPIR-V Sec 3.22 + SPV_OPERAND_TYPE_LOOP_CONTROL, // SPIR-V Sec 3.23 + SPV_OPERAND_TYPE_FUNCTION_CONTROL, // SPIR-V Sec 3.24 + SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26 + SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR // The remaining operand types are only used internally by the assembler. // There are two categories: diff --git a/source/operand.cpp b/source/operand.cpp index 7b2b98f2d1..d4b64a8b82 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -208,6 +208,8 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_MEMORY_ACCESS: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: return "memory access"; + case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: + return "shading rate"; case SPV_OPERAND_TYPE_SCOPE_ID: return "scope ID"; case SPV_OPERAND_TYPE_GROUP_OPERATION: @@ -360,6 +362,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) { case SPV_OPERAND_TYPE_LOOP_CONTROL: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_MEMORY_ACCESS: + case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: return true; diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 1d7017d118..5b9eed6407 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2018 Google LLC. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -230,6 +232,12 @@ class BuiltInsValidator { spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration, const Instruction& inst); + spv_result_t ValidatePrimitiveShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst); + + spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration, + const Instruction& inst); + // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -383,6 +391,16 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidatePrimitiveShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -3314,6 +3332,142 @@ spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4486) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassOutput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Output storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + switch (execution_model) { + case SpvExecutionModelVertex: + case SpvExecutionModelGeometry: + case SpvExecutionModelMeshNV: + break; + default: { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with Vertex, Geometry, or MeshNV " + "execution models. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back( + std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference, + this, decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(4492) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateShadingRateAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateShadingRateAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with the Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateShadingRateAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); @@ -3514,6 +3668,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInRayGeometryIndexKHR: { // No validation rules (for the moment). break; + + case SpvBuiltInPrimitiveShadingRateKHR: + return ValidatePrimitiveShadingRateAtDefinition(decoration, inst); + case SpvBuiltInShadingRateKHR: + return ValidateShadingRateAtDefinition(decoration, inst); } } return SPV_SUCCESS; diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index cc9bda67cf..4248caa9b1 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -1,4 +1,6 @@ // Copyright (c) 2018 Google LLC. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights +// reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -3723,6 +3725,108 @@ OpDecorate %int0 BuiltIn Position EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +INSTANTIATE_TEST_SUITE_P( + PrimitiveShadingRateOutputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("PrimitiveShadingRateKHR"), Values("Vertex", "Geometry"), + Values("Output"), Values("%u32"), + Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + PrimitiveShadingRateMeshOutputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("PrimitiveShadingRateKHR"), Values("MeshNV"), + Values("Output"), Values("%u32"), + Values("OpCapability FragmentShadingRateKHR\nOpCapability " + "MeshShadingNV\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\nOpExtension " + "\"SPV_NV_mesh_shader\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + PrimitiveShadingRateInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("PrimitiveShadingRateKHR"), Values("Fragment"), Values("Output"), + Values("%u32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484 "), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn PrimitiveShadingRateKHR to be used " + "only with Vertex, Geometry, or MeshNV execution models.")))); + +INSTANTIATE_TEST_SUITE_P( + PrimitiveShadingRateInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("PrimitiveShadingRateKHR"), Values("Vertex"), Values("Input"), + Values("%u32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485 "), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn PrimitiveShadingRateKHR to be only " + "used for variables with Output storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + PrimitiveShadingRateInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("PrimitiveShadingRateKHR"), Values("Vertex"), Values("Output"), + Values("%f32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485 "), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn PrimitiveShadingRateKHR " + "variable needs to be a 32-bit int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + ShadingRateInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("ShadingRateKHR"), Values("Fragment"), Values("Input"), + Values("%u32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + ShadingRateInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("ShadingRateKHR"), Values("Vertex"), Values("Input"), + Values("%u32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-ShadingRateKHR-ShadingRateKHR-04490 "), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn ShadingRateKHR to be used " + "only with the Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + ShadingRateInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("ShadingRateKHR"), Values("Fragment"), Values("Output"), + Values("%u32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-ShadingRateKHR-ShadingRateKHR-04491 "), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn ShadingRateKHR to be only " + "used for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + ShadingRateInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("ShadingRateKHR"), Values("Fragment"), Values("Input"), + Values("%f32"), Values("OpCapability FragmentShadingRateKHR\n"), + Values("OpExtension \"SPV_KHR_fragment_shading_rate\"\n"), + Values("VUID-ShadingRateKHR-ShadingRateKHR-04492 "), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn ShadingRateKHR " + "variable needs to be a 32-bit int scalar.")))); } // namespace } // namespace val } // namespace spvtools