From f37547c73a981bcf3f8b1a471e3000e606dd41a8 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 20 Jan 2021 07:40:31 -0800 Subject: [PATCH] spirv-val: Add Vulkan EXT builtins (#4115) --- source/val/validate_builtins.cpp | 353 ++++++++++++++++++++++++++++++- source/val/validation_state.cpp | 24 +++ test/val/val_builtins_test.cpp | 178 ++++++++++++++++ 3 files changed, 549 insertions(+), 6 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 7fb99089c..3c9df9fc2 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -120,7 +120,7 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumVUIDBuiltins = 29; +const static uint32_t NumVUIDBuiltins = 33; typedef struct { SpvBuiltIn builtIn; @@ -158,6 +158,10 @@ std::array builtinVUIDInfo = {{ {SpvBuiltInWorldRayOriginKHR, {4431, 4432, 4433}}, {SpvBuiltInLaunchIdKHR, {4266, 4267, 4268}}, {SpvBuiltInLaunchSizeKHR, {4269, 4270, 4271}}, + {SpvBuiltInFragInvocationCountEXT, {4217, 4218, 4219}}, + {SpvBuiltInFragSizeEXT, {4220, 4221, 4222}}, + {SpvBuiltInFragStencilRefEXT, {4223, 4224, 4225}}, + {SpvBuiltInFullyCoveredEXT, {4232, 4233, 4234}}, // clang-format off } }; @@ -314,6 +318,14 @@ class BuiltInsValidator { const Instruction& inst); spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration, + const Instruction& inst); // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst); @@ -472,6 +484,26 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateFragInvocationCountAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFragSizeAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFragStencilRefAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFullyCoveredAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, @@ -525,6 +557,9 @@ class BuiltInsValidator { spv_result_t ValidateBool( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateI( + const Decoration& decoration, const Instruction& inst, + const std::function& diag); spv_result_t ValidateI32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -717,6 +752,22 @@ spv_result_t BuiltInsValidator::ValidateBool( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateI( + const Decoration& decoration, const Instruction& inst, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + if (!_.IsIntScalarType(underlying_type)) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar."); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateI32( const Decoration& decoration, const Instruction& inst, const std::function& diag) { @@ -3296,6 +3347,287 @@ spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration, + const Instruction& inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + return ValidateFragInvocationCountAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " 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) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with 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::ValidateFragInvocationCountAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI32Vec( + decoration, inst, 2, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a 2-component 32-bit int vector. " + << message; + })) { + return error; + } + } + + return ValidateFragSizeAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragSizeAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " 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) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with 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::ValidateFragSizeAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a int scalar. " + << message; + })) { + return error; + } + } + + return ValidateFragStencilRefAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassOutput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " 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_) { + if (execution_model != SpvExecutionModelFragment) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with 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::ValidateFragStencilRefAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateBool( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a bool scalar. " + << message; + })) { + return error; + } + } + + return ValidateFullyCoveredAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " 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) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with 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::ValidateFullyCoveredAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { @@ -3793,6 +4125,20 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInDeviceIndex: { return ValidateDeviceIndexAtDefinition(decoration, inst); } + case SpvBuiltInFragInvocationCountEXT: { + // alias SpvBuiltInInvocationsPerPixelNV + return ValidateFragInvocationCountAtDefinition(decoration, inst); + } + case SpvBuiltInFragSizeEXT: { + // alias SpvBuiltInFragmentSizeNV + return ValidateFragSizeAtDefinition(decoration, inst); + } + case SpvBuiltInFragStencilRefEXT: { + return ValidateFragStencilRefAtDefinition(decoration, inst); + } + case SpvBuiltInFullyCoveredEXT:{ + return ValidateFullyCoveredAtDefinition(decoration, inst); + } // Ray tracing builtins case SpvBuiltInHitKindKHR: // alias SpvBuiltInHitKindNV case SpvBuiltInHitTNV: // NOT present in KHR @@ -3828,13 +4174,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInBaryCoordSmoothCentroidAMD: case SpvBuiltInBaryCoordSmoothSampleAMD: case SpvBuiltInBaryCoordPullModelAMD: - case SpvBuiltInFragStencilRefEXT: case SpvBuiltInViewportMaskNV: case SpvBuiltInSecondaryPositionNV: case SpvBuiltInSecondaryViewportMaskNV: case SpvBuiltInPositionPerViewNV: case SpvBuiltInViewportMaskPerViewNV: - case SpvBuiltInFullyCoveredEXT: case SpvBuiltInMax: case SpvBuiltInTaskCountNV: case SpvBuiltInPrimitiveCountNV: @@ -3846,9 +4190,6 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInMeshViewIndicesNV: case SpvBuiltInBaryCoordNV: case SpvBuiltInBaryCoordNoPerspNV: - case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT - case SpvBuiltInInvocationsPerPixelNV: // alias - // SpvBuiltInFragInvocationCountEXT // No validation rules (for the moment). break; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 92b51c741..b9269db7c 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1340,12 +1340,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-FragDepth-FragDepth-04215); case 4216: return VUID_WRAP(VUID-FragDepth-FragDepth-04216); + case 4217: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217); + case 4218: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218); + case 4219: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219); + case 4220: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220); + case 4221: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221); + case 4222: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222); + case 4223: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223); + case 4224: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224); + case 4225: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225); case 4229: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229); case 4230: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230); case 4231: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231); + case 4232: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232); + case 4233: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233); + case 4234: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234); case 4236: return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236); case 4237: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 66e73be6f..bbcdbb114 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -3941,6 +3941,184 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "According to the Vulkan spec BuiltIn ShadingRateKHR " "variable needs to be a 32-bit int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Input"), Values("%u32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("FragInvocationCountEXT"), Values("Vertex"), Values("Input"), + Values("%u32"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragInvocationCountEXT " + "to be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Output"), Values("%u32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragInvocationCountEXT to be only " + "used for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Input"), Values("%f32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragInvocationCountEXT " + "variable needs to be a 32-bit int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Vertex"), Values("Input"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04220"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragSizeEXT to be " + "used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("FragSizeEXT"), Values("Fragment"), Values("Output"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04221"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragSizeEXT to be only " + "used for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"), + Values("%u32vec3"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04222"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragSizeEXT variable " + "needs to be a 2-component 32-bit int vector.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefOutputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Vertex"), Values("Output"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04223"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragStencilRefEXT to " + "be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Input"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04224"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragStencilRefEXT to be only used " + "for variables with Output storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"), + Values("%f32", "%f64", "%u32vec2"), + Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04225"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragStencilRefEXT " + "variable needs to be a int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Vertex"), Values("Input"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04232"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FullyCoveredEXT to " + "be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Output"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04233"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FullyCoveredEXT to be only used " + "for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"), + Values("%f32"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04234"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FullyCoveredEXT variable " + "needs to be a bool scalar.")))); + } // namespace } // namespace val } // namespace spvtools