Add validation support for MeshEXT based on the spec update PR https://github.com/KhronosGroup/Vulkan-Docs/pull/2475 (#6171)

diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index d25ebaf..2c17264 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -373,6 +373,13 @@
   spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
       const Decoration& decoration, const Instruction& inst);
 
+  // Used as a common method for validating MeshEXT builtins
+  spv_result_t ValidateMeshEXTBuiltinInterfaceRules(
+      const Decoration& decoration, const Instruction& inst,
+      spv::Op scalar_type, uint32_t array_type_vuid, uint32_t array_size_vuid,
+      uint32_t block_array_size_vuid, uint32_t interface_vuid,
+      uint32_t perprim_deco_vuid);
+
   // The following section contains functions which are called when id defined
   // by |referenced_inst| is
   // 1. referenced by |referenced_from_inst|
@@ -590,8 +597,9 @@
   spv_result_t ValidateBool(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
-  spv_result_t ValidateBlockBoolOrArrayedBool(
+  spv_result_t ValidateBlockTypeOrArrayedType(
       const Decoration& decoration, const Instruction& inst,
+      bool& present_in_block, spv::Op expected_scalar_type,
       const std::function<spv_result_t(const std::string& message)>& diag);
   spv_result_t ValidateI(
       const Decoration& decoration, const Instruction& inst,
@@ -675,13 +683,18 @@
   // UniformConstant".
   std::string GetStorageClassDesc(const Instruction& inst) const;
 
+  uint64_t GetArrayLength(uint32_t interface_var_id);
+
   // Updates inner working of the class. Is called sequentially for every
   // instruction.
   void Update(const Instruction& inst);
 
-  // Check if "inst" is an interface variable
-  // or type of a interface varibale of any mesh entry point
-  bool isMeshInterfaceVar(const Instruction& inst) {
+  // Check if "inst" is an interface variable or type of a interface varibale
+  // of any mesh entry point. Populate entry_point_interface_id with all
+  // entry points and interface variables that refer to the "inst"
+  bool isMeshInterfaceVar(
+      const Instruction& inst,
+      std::map<uint32_t, uint32_t>& entry_point_interface_id) {
     auto getUnderlyingTypeId = [&](const Instruction* ifxVar) {
       auto pointerTypeInst = _.FindDef(ifxVar->type_id());
       auto typeInst = _.FindDef(pointerTypeInst->GetOperandAs<uint32_t>(2));
@@ -699,15 +712,34 @@
           for (auto interface : desc.interfaces) {
             if (inst.opcode() == spv::Op::OpTypeStruct) {
               auto varInst = _.FindDef(interface);
-              if (inst.id() == getUnderlyingTypeId(varInst)) return true;
+              if (inst.id() == getUnderlyingTypeId(varInst)) {
+                entry_point_interface_id[entry_point] = interface;
+                break;
+              }
             } else if (inst.id() == interface) {
-              return true;
+              entry_point_interface_id[entry_point] = interface;
+              break;
             }
           }
         }
       }
     }
-    return false;
+    return !entry_point_interface_id.empty();
+  }
+
+  bool HasInterfaceVariableForMeshEntryPoint(spv::BuiltIn builtin,
+                                             uint32_t entry_point) {
+    const auto& entry_points = mesh_builtin_entry_point_.find(builtin);
+    if (entry_points == mesh_builtin_entry_point_.end()) return false;
+
+    return std::any_of(
+        entry_points->second.begin(), entry_points->second.end(),
+        [entry_point](const uint32_t& ep) { return entry_point == ep; });
+  }
+  void RegisterMeshEntryPointForBuiltin(spv::BuiltIn builtin,
+                                        uint32_t entry_point) {
+    auto& entry_points = mesh_builtin_entry_point_[builtin];
+    entry_points.insert(entry_point);
   }
 
   ValidationState_t& _;
@@ -730,6 +762,10 @@
 
   // Execution models with which the current function can be called.
   std::set<spv::ExecutionModel> execution_models_;
+
+  // Mesh Builtins which are part of interface variables corresponding to an
+  // entry point
+  std::map<spv::BuiltIn, std::set<uint32_t>> mesh_builtin_entry_point_;
 };
 
 void BuiltInsValidator::Update(const Instruction& inst) {
@@ -807,6 +843,29 @@
   return ss.str();
 }
 
+uint64_t BuiltInsValidator::GetArrayLength(uint32_t interface_var_id) {
+  uint32_t underlying_type;
+  spv::StorageClass storage_class;
+  uint64_t array_len = -1;
+  const Instruction* inst = _.FindDef(interface_var_id);
+  if (inst->opcode() != spv::Op::OpVariable) {
+    return -1;
+  }
+
+  if (!_.GetPointerTypeInfo(inst->type_id(), &underlying_type,
+                            &storage_class)) {
+    return 0;
+  }
+  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
+    // Get the array length
+    const auto length_id = _.FindDef(underlying_type)->word(3u);
+    if (!_.EvalConstantValUint64(length_id, &array_len)) {
+      return 0;
+    }
+  }
+  return array_len;
+}
+
 spv_result_t BuiltInsValidator::ValidateBool(
     const Decoration& decoration, const Instruction& inst,
     const std::function<spv_result_t(const std::string& message)>& diag) {
@@ -823,25 +882,50 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t BuiltInsValidator::ValidateBlockBoolOrArrayedBool(
-    const Decoration& decoration, const Instruction& inst,
+spv_result_t BuiltInsValidator::ValidateBlockTypeOrArrayedType(
+    const Decoration& decoration, const Instruction& inst, bool& isBlock,
+    spv::Op expected_scalar_type,
     const std::function<spv_result_t(const std::string& message)>& diag) {
   uint32_t underlying_type = 0;
+  int64_t array_len = -1;
+  isBlock = true;
   if (spv_result_t error =
           GetUnderlyingType(_, decoration, inst, &underlying_type)) {
     return error;
   }
   // Strip the array, if present.
   if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
+    // Get the array length
+    const auto length_id = _.FindDef(underlying_type)->word(3u);
+    if (!_.EvalConstantValInt64(length_id, &array_len)) {
+      return diag(GetDefinitionDesc(decoration, inst) +
+                  " Failed to find the array length.");
+    }
     underlying_type = _.FindDef(underlying_type)->word(2u);
+    isBlock = false;
   } else if (!_.HasDecoration(inst.id(), spv::Decoration::Block)) {
     // If not in array, and bool is in a struct, must be in a Block struct
     return diag(GetDefinitionDesc(decoration, inst) +
                 " Scalar boolean must be in a Block.");
   }
 
-  if (!_.IsBoolScalarType(underlying_type)) {
-    return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
+  switch (expected_scalar_type) {
+    case spv::Op::OpTypeBool:
+      if (!_.IsBoolScalarType(underlying_type)) {
+        return diag(GetDefinitionDesc(decoration, inst) +
+                    " is not a bool scalar.");
+      }
+      break;
+    case spv::Op::OpTypeInt:
+      if (!_.IsSignedIntScalarType(underlying_type)) {
+        return diag(GetDefinitionDesc(decoration, inst) +
+                    " is not a signed integer scalar.");
+      }
+      break;
+    default:
+      assert(0 && "Unhandled scalar type");
+      return diag(GetDefinitionDesc(decoration, inst) +
+                  " is not a recognized scalar type.");
   }
 
   return SPV_SUCCESS;
@@ -2189,9 +2273,22 @@
 spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
   if (spvIsVulkanEnv(_.context()->target_env)) {
+    if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
+      uint32_t array_type_vuid = 10595;
+      uint32_t interface_vuid = 0;
+      uint32_t array_size_vuid = 10596;
+      uint32_t block_array_size_vuid = 10597;
+      uint32_t perprim_deco_vuid = 7040;
+      if (spv_result_t error = ValidateMeshEXTBuiltinInterfaceRules(
+              decoration, inst, spv::Op::OpTypeInt, array_type_vuid,
+              array_size_vuid, block_array_size_vuid, interface_vuid,
+              perprim_deco_vuid)) {
+        return error;
+      }
+    }
     // PrimitiveId can be a per-primitive variable for mesh shader stage.
     // In such cases variable will have an array of 32-bit integers.
-    if (decoration.struct_member_index() != Decoration::kInvalidMember) {
+    else if (decoration.struct_member_index() != Decoration::kInvalidMember) {
       // This must be a 32-bit int scalar.
       if (spv_result_t error = ValidateI32(
               decoration, inst,
@@ -2217,17 +2314,6 @@
         return error;
       }
     }
-
-    if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
-      if (isMeshInterfaceVar(inst) &&
-          !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
-        return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-               << _.VkErrorID(7040)
-               << "According to the Vulkan spec the variable decorated with "
-                  "Builtin PrimitiveId within the MeshEXT Execution Model must "
-                  "also be decorated with the PerPrimitiveEXT decoration. ";
-      }
-    }
   }
 
   // Seed at reference checks with this built-in.
@@ -2796,12 +2882,100 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateMeshEXTBuiltinInterfaceRules(
+    const Decoration& decoration, const Instruction& inst, spv::Op scalar_type,
+    uint32_t array_type_vuid, uint32_t array_size_vuid,
+    uint32_t block_array_size_vuid, uint32_t interface_vuid,
+    uint32_t perprim_deco_vuid) {
+  bool is_block = false;
+  const spv::BuiltIn builtin = decoration.builtin();
+  // Validate the type of the builtin and if it's part of a block or an array
+  if (spv_result_t error = ValidateBlockTypeOrArrayedType(
+          decoration, inst, is_block, scalar_type,
+          [this, &inst, &decoration,
+           &array_type_vuid](const std::string& message) -> spv_result_t {
+            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                   << _.VkErrorID(array_type_vuid) << "According to the "
+                   << spvLogStringForEnv(_.context()->target_env)
+                   << " spec BuiltIn "
+                   << _.grammar().lookupOperandName(
+                          SPV_OPERAND_TYPE_BUILT_IN,
+                          (uint32_t)decoration.builtin())
+                   << " variable needs to be a either a boolean or an "
+                      "array of booleans."
+                   << message;
+          })) {
+    return error;
+  }
+
+  // Validate that the builtin is part of the mesh interface
+  std::map<uint32_t, uint32_t> entry_interface_id_map;
+  bool found = isMeshInterfaceVar(inst, entry_interface_id_map);
+  if (!found) {
+    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+           << _.VkErrorID(interface_vuid) << "Declaration of builtin type"
+           << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                            (uint32_t)builtin)
+           << " not found as interface variable of any meshEXT entry point. ";
+  }
+  for (const auto& id : entry_interface_id_map) {
+    uint32_t entry_point_id = id.first;
+    uint32_t interface_var_id = id.second;
+    if (!HasInterfaceVariableForMeshEntryPoint(builtin, entry_point_id)) {
+      RegisterMeshEntryPointForBuiltin(decoration.builtin(), entry_point_id);
+    } else {
+      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+             << _.VkErrorID(interface_vuid)
+             << "There must be only one declaration of the "
+             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                              (uint32_t)builtin)
+             << " associated with a entry point's interface. "
+             << GetIdDesc(*_.FindDef(interface_var_id));
+    }
+    if (GetArrayLength(interface_var_id) !=
+        _.GetOutputPrimitivesEXT(entry_point_id)) {
+      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+             << _.VkErrorID(is_block ? block_array_size_vuid : array_size_vuid)
+             << " The size of the array decorated with "
+             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                              (uint32_t)builtin)
+             << " must match the value specified by OutputPrimitivesEXT. ";
+    }
+  }
+  if (!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
+    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+           << _.VkErrorID(perprim_deco_vuid)
+           << "According to the Vulkan spec the variable decorated with "
+              "Builtin "
+           << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                            (uint32_t)builtin)
+           << " within the MeshEXT Execution Model must also be "
+           << "decorated with the PerPrimitiveEXT decoration. ";
+  }
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
   if (spvIsVulkanEnv(_.context()->target_env)) {
-    // This can be a per-primitive variable for mesh shader stage.
+    if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
+      const spv::BuiltIn label = decoration.builtin();
+      uint32_t array_type_vuid = (label == spv::BuiltIn::Layer) ? 10592 : 10601;
+      uint32_t interface_vuid = 0;
+      uint32_t array_size_vuid = (label == spv::BuiltIn::Layer) ? 10593 : 10602;
+      uint32_t block_array_size_vuid =
+          (label == spv::BuiltIn::Layer) ? 10594 : 10603;
+      uint32_t perprim_deco_vuid = (label == spv::BuiltIn::Layer) ? 7039 : 7060;
+      if (spv_result_t error = ValidateMeshEXTBuiltinInterfaceRules(
+              decoration, inst, spv::Op::OpTypeInt, array_type_vuid,
+              array_size_vuid, block_array_size_vuid, interface_vuid,
+              perprim_deco_vuid)) {
+        return error;
+      }
+    }
+    // This can be a per-primitive variable for NV mesh shader stage.
     // In such cases variable will have an array of 32-bit integers.
-    if (decoration.struct_member_index() != Decoration::kInvalidMember) {
+    else if (decoration.struct_member_index() != Decoration::kInvalidMember) {
       // This must be a 32-bit int scalar.
       if (spv_result_t error = ValidateI32(
               decoration, inst,
@@ -2820,39 +2994,23 @@
               })) {
         return error;
       }
-    } else {
-      if (spv_result_t error = ValidateOptionalArrayedI32(
-              decoration, inst,
-              [this, &decoration,
-               &inst](const std::string& message) -> spv_result_t {
-                uint32_t vuid =
-                    (decoration.builtin() == spv::BuiltIn::Layer) ? 4276 : 4408;
-                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-                       << _.VkErrorID(vuid)
-                       << "According to the Vulkan spec BuiltIn "
-                       << _.grammar().lookupOperandName(
-                              SPV_OPERAND_TYPE_BUILT_IN,
-                              (uint32_t)decoration.builtin())
-                       << "variable needs to be a 32-bit int scalar. "
-                       << message;
-              })) {
-        return error;
-      }
-    }
-
-    if (isMeshInterfaceVar(inst) &&
-        _.HasCapability(spv::Capability::MeshShadingEXT) &&
-        !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
-      const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
-      uint32_t vkerrid = (label == spv::BuiltIn::Layer) ? 7039 : 7060;
-      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-             << _.VkErrorID(vkerrid)
-             << "According to the Vulkan spec the variable decorated with "
-                "Builtin "
-             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
-                                              decoration.params()[0])
-             << " within the MeshEXT Execution Model must also be decorated "
-                "with the PerPrimitiveEXT decoration. ";
+    } else if (spv_result_t error = ValidateOptionalArrayedI32(
+                   decoration, inst,
+                   [this, &decoration,
+                    &inst](const std::string& message) -> spv_result_t {
+                     uint32_t vuid =
+                         (decoration.builtin() == spv::BuiltIn::Layer) ? 4276
+                                                                       : 4408;
+                     return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                            << _.VkErrorID(vuid)
+                            << "According to the Vulkan spec BuiltIn "
+                            << _.grammar().lookupOperandName(
+                                   SPV_OPERAND_TYPE_BUILT_IN,
+                                   (uint32_t)decoration.builtin())
+                            << "variable needs to be a 32-bit int scalar. "
+                            << message;
+                   })) {
+      return error;
     }
   }
 
@@ -3987,30 +4145,33 @@
 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,
-                            (uint32_t)decoration.builtin())
-                     << " variable needs to be a 32-bit int scalar. "
-                     << message;
-            })) {
+    if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
+      uint32_t array_type_vuid = 10598;
+      uint32_t interface_vuid = 0;
+      uint32_t array_size_vuid = 10599;
+      uint32_t block_array_size_vuid = 10600;
+      uint32_t perprim_deco_vuid = 7059;
+      if (spv_result_t error = ValidateMeshEXTBuiltinInterfaceRules(
+              decoration, inst, spv::Op::OpTypeInt, array_type_vuid,
+              array_size_vuid, block_array_size_vuid, interface_vuid,
+              perprim_deco_vuid)) {
+        return error;
+      }
+    } else 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,
+                                   (uint32_t)decoration.builtin())
+                            << " variable needs to be a 32-bit int scalar. "
+                            << message;
+                   })) {
       return error;
     }
-    if (isMeshInterfaceVar(inst) &&
-        _.HasCapability(spv::Capability::MeshShadingEXT) &&
-        !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
-      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-             << _.VkErrorID(7059)
-             << "The variable decorated with PrimitiveShadingRateKHR "
-                "within the MeshEXT Execution Model must also be "
-                "decorated with the PerPrimitiveEXT decoration";
-    }
   }
 
   // Seed at reference checks with this built-in.
@@ -4365,32 +4526,20 @@
           return error;
         }
         break;
-      case spv::BuiltIn::CullPrimitiveEXT:
-        if (spv_result_t error = ValidateBlockBoolOrArrayedBool(
-                decoration, inst,
-                [this, &inst, &decoration,
-                 &vuid](const std::string& message) -> spv_result_t {
-                  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,
-                                (uint32_t)decoration.builtin())
-                         << " variable needs to be a either a boolean or an "
-                            "array of booleans."
-                         << message;
-                })) {
+      case spv::BuiltIn::CullPrimitiveEXT: {
+        uint32_t array_type_vuid = vuid;
+        uint32_t interface_vuid = 10591;
+        uint32_t array_size_vuid = 10589;
+        uint32_t block_array_size_vuid = 10590;
+        uint32_t perprim_deco_vuid = 7038;
+        if (spv_result_t error = ValidateMeshEXTBuiltinInterfaceRules(
+                decoration, inst, spv::Op::OpTypeBool, array_type_vuid,
+                array_size_vuid, block_array_size_vuid, interface_vuid,
+                perprim_deco_vuid)) {
           return error;
         }
-        if (!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
-          return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-                 << _.VkErrorID(7038)
-                 << "The variable decorated with CullPrimitiveEXT within the "
-                    "MeshEXT Execution Model must also be decorated with the "
-                    "PerPrimitiveEXT decoration ";
-        }
         break;
+      }
       default:
         assert(0 && "Unexpected mesh EXT builtin");
     }
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 8041352..d4a8dda 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -2634,6 +2634,30 @@
       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeFloat-10370);
     case 10583:
       return VUID_WRAP(VUID-StandaloneSpirv-Component-10583);
+    case 10589:
+      return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-10589);
+    case 10590:
+      return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-10590);
+    case 10591:
+      return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-10591);
+    case 10592:
+      return VUID_WRAP(VUID-Layer-Layer-10592);
+    case 10593:
+      return VUID_WRAP(VUID-Layer-Layer-10593);
+    case 10594:
+      return VUID_WRAP(VUID-Layer-Layer-10594);
+    case 10598:
+      return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10598);
+    case 10599:
+      return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10599);
+    case 10600:
+      return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10600);
+    case 10601:
+      return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-10601);
+    case 10602:
+      return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-10602);
+    case 10603:
+      return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-10603);
     case 10684:
       return VUID_WRAP(VUID-StandaloneSpirv-None-10684);
     case 10685:
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index 2032ff2..c194128 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -4666,49 +4666,6 @@
               AnyVUID("VUID-PrimitiveId-PrimitiveId-07040"));
 }
 
-TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerWithPerPrimitiveEXT) {
-  const std::string text = R"(
-          OpCapability MeshShadingEXT
-          OpCapability Shader
-          OpExtension "SPV_EXT_mesh_shader"
-          OpMemoryModel Logical GLSL450
-          OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_Layer
-          OpExecutionMode %MainMesh OutputPrimitivesNV 1
-          OpExecutionMode %MainMesh OutputVertices 3
-          OpExecutionMode %MainMesh OutputTrianglesNV
-          OpExecutionMode %MainMesh LocalSize 1 1 1
-          OpSource Slang 1
-          OpName %MainMesh "MainMesh"
-          OpDecorate %gl_Layer BuiltIn Layer
-  %void = OpTypeVoid
-     %9 = OpTypeFunction %void
-  %uint = OpTypeInt 32 0
-%uint_3 = OpConstant %uint 3
-%uint_1 = OpConstant %uint 1
- %float = OpTypeFloat 32
-   %int = OpTypeInt 32 1
- %int_1 = OpConstant %int 1
- %int_3 = OpConstant %int 3
-%uint_0 = OpConstant %uint 0
-%v3float = OpTypeVector %float 3
-%_ptr_Output_v3float = OpTypePointer Output %v3float
-%v3uint = OpTypeVector %uint 3
-%_ptr_Output_v3uint = OpTypePointer Output %v3uint
-%_ptr_Output_int = OpTypePointer Output %int
-%_arr_int_int_1 = OpTypeArray %int %int_1
-%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
-%gl_Layer = OpVariable %_ptr_Output__arr_int_int_1 Output
-%MainMesh = OpFunction %void None %9
-    %25 = OpLabel
-          OpSetMeshOutputsEXT %uint_3 %uint_1
-          OpReturn
-          OpFunctionEnd
-)";
-
-  CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
-  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
-  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-07039"));
-}
 
 TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexWithPerPrimitiveEXT) {
   const std::string text = R"(
@@ -5214,7 +5171,7 @@
       AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041"));
 }
 
-TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXT) {
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXTInBlock) {
   const std::string text = R"(
       OpCapability MeshShadingEXT
       OpExtension "SPV_EXT_mesh_shader"
@@ -5255,6 +5212,50 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
 }
 
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTBlockArraySize) {
+  const std::string text = R"(
+        OpCapability MeshShadingEXT
+        OpExtension "SPV_EXT_mesh_shader"
+   %1 = OpExtInstImport "GLSL.std.450"
+        OpMemoryModel Logical GLSL450
+        OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+        OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+        OpExecutionMode %main OutputVertices 81
+        OpExecutionMode %main OutputPrimitivesEXT 32
+        OpExecutionMode %main OutputTrianglesEXT
+        OpSource GLSL 450
+        OpSourceExtension "GL_EXT_mesh_shader"
+        OpName %main "main"
+        OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+        OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_CullPrimitiveEXT"
+        OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+        OpDecorate %gl_MeshPerPrimitiveEXT Block
+        OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn CullPrimitiveEXT
+        OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+  %void = OpTypeVoid
+   %3 = OpTypeFunction %void
+  %uint = OpTypeInt 32 0
+  %uint_32 = OpConstant %uint 32
+  %uint_16 = OpConstant %uint 16
+  %uint_1 = OpConstant %uint 1
+  %int = OpTypeInt 32 1
+  %bool = OpTypeBool
+  %gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+  %_arr_gl_MeshPerPrimitiveEXT_uint_16 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_16
+  %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_16 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_16
+  %gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_16 Output
+  %main = OpFunction %void None %3
+   %5 = OpLabel
+        OpReturn
+        OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-10590"));
+}
+
 TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXTMissingBlock) {
   const std::string text = R"(
       OpCapability MeshShadingEXT
@@ -5343,7 +5344,7 @@
 }
 
 // from https://github.com/KhronosGroup/SPIRV-Tools/issues/5980
-TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveArrayOfBool) {
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXTArrayOfBool) {
   const std::string text = R"(
                OpCapability MeshShadingEXT
                OpExtension "SPV_EXT_mesh_shader"
@@ -5393,7 +5394,7 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
 }
 
-TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveArrayOfBool) {
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTArrayType) {
   const std::string text = R"(
                OpCapability MeshShadingEXT
                OpExtension "SPV_EXT_mesh_shader"
@@ -5444,6 +5445,118 @@
               AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
 }
 
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTArrayOfBoolSize) {
+  const std::string text = R"(
+          OpCapability MeshShadingEXT
+          OpExtension "SPV_EXT_mesh_shader"
+          OpMemoryModel Logical GLSL450
+          OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5
+          OpExecutionMode %main LocalSize 2 1 1
+          OpExecutionMode %main OutputTrianglesEXT
+          OpExecutionMode %main OutputVertices 2
+          OpExecutionMode %main OutputPrimitivesEXT 2
+          OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+          OpDecorate %gl_Position BuiltIn Position
+          OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+          OpDecorate %5 BuiltIn CullPrimitiveEXT
+          OpDecorate %5 PerPrimitiveEXT
+  %uint = OpTypeInt 32 0
+%uint_2 = OpConstant %uint 2
+%uint_4 = OpConstant %uint 4
+  %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+ %float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+%v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_bool_uint_4 = OpTypeArray %bool %uint_4
+%_ptr_Output__arr_bool_uint_4 = OpTypePointer Output %_arr_bool_uint_4
+  %void = OpTypeVoid
+    %21 = OpTypeFunction %void
+%_ptr_Output_bool = OpTypePointer Output %bool
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+     %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+     %5 = OpVariable %_ptr_Output__arr_bool_uint_4 Output
+  %main = OpFunction %void None %21
+    %23 = OpLabel
+    %24 = OpLoad %uint %gl_LocalInvocationIndex
+          OpSetMeshOutputsEXT %uint_2 %uint_2
+    %25 = OpAccessChain %_ptr_Output_bool %5 %24
+          OpStore %25 %false
+          OpReturn
+          OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-10589"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTInterfaceVariable) {
+  const std::string text = R"(
+         OpCapability MeshShadingEXT
+         OpExtension "SPV_EXT_mesh_shader"
+         OpMemoryModel Logical GLSL450
+         OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5 %gl_MeshPrimitivesEXT
+         OpExecutionMode %main LocalSize 2 1 1
+         OpExecutionMode %main OutputTrianglesEXT
+         OpExecutionMode %main OutputVertices 2
+         OpExecutionMode %main OutputPrimitivesEXT 2
+         OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+         OpDecorate %gl_Position BuiltIn Position
+         OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+         OpDecorate %5 BuiltIn CullPrimitiveEXT
+         OpDecorate %5 PerPrimitiveEXT
+         OpDecorate %gl_MeshPerPrimitiveEXT Block
+         OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn CullPrimitiveEXT
+         OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+ %uint = OpTypeInt 32 0
+%uint_2 = OpConstant %uint 2
+ %bool = OpTypeBool
+%false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+%v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_bool_uint_2 = OpTypeArray %bool %uint_2
+%_ptr_Output__arr_bool_uint_2 = OpTypePointer Output %_arr_bool_uint_2
+ %void = OpTypeVoid
+   %21 = OpTypeFunction %void
+%_ptr_Output_bool = OpTypePointer Output %bool
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+    %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+    %5 = OpVariable %_ptr_Output__arr_bool_uint_2 Output
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_2 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_2
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_2 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_2
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_2 Output
+ %main = OpFunction %void None %21
+   %23 = OpLabel
+   %24 = OpLoad %uint %gl_LocalInvocationIndex
+         OpSetMeshOutputsEXT %uint_2 %uint_2
+   %25 = OpAccessChain %_ptr_Output_bool %5 %24
+         OpStore %25 %false
+         OpReturn
+         OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-10591"));
+}
+
 TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTStorageClass) {
   const std::string text = R"(
       OpCapability MeshShadingEXT
@@ -5619,6 +5732,790 @@
               AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07034"));
 }
 
+TEST_F(ValidateBuiltIns, VulkanBuiltinLayerInBlockMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+      OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_Layer"
+      OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+      OpDecorate %gl_MeshPerPrimitiveEXT Block
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn Layer
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, VulkanBuiltinLayerAsArrayOfIntMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_Layer
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpDecorate %gl_Layer BuiltIn Layer
+      OpDecorate %gl_Layer PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_Layer_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_Layer_uint_32 = OpTypePointer Output %_arr_gl_Layer_uint_32
+%gl_Layer = OpVariable %_ptr_Output__arr_gl_Layer_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerArrayTypeMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_Layer
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpDecorate %gl_Layer BuiltIn Layer
+      OpDecorate %gl_Layer PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_Layer_uint_32 = OpTypeArray %bool %uint_32
+%_ptr_Output__arr_gl_Layer_uint_32 = OpTypePointer Output %_arr_gl_Layer_uint_32
+%gl_Layer = OpVariable %_ptr_Output__arr_gl_Layer_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-10592"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerInBlockMeshEXTType) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+      OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_Layer"
+      OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+      OpDecorate %gl_MeshPerPrimitiveEXT Block
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn Layer
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-10592"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerArrayOfIntSizeMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_Layer
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 16
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpDecorate %gl_Layer BuiltIn Layer
+      OpDecorate %gl_Layer PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_Layer_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_Layer_uint_32 = OpTypePointer Output %_arr_gl_Layer_uint_32
+%gl_Layer = OpVariable %_ptr_Output__arr_gl_Layer_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-10593"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerInBlockArraySizeMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 16
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+      OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_Layer"
+      OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+      OpDecorate %gl_MeshPerPrimitiveEXT Block
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn Layer
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-10594"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinLayerWithPerPrimitiveEXT) {
+  const std::string text = R"(
+          OpCapability MeshShadingEXT
+          OpCapability Shader
+          OpExtension "SPV_EXT_mesh_shader"
+          OpMemoryModel Logical GLSL450
+          OpEntryPoint MeshEXT %MainMesh "MainMesh" %gl_Layer
+          OpExecutionMode %MainMesh OutputPrimitivesNV 1
+          OpExecutionMode %MainMesh OutputVertices 3
+          OpExecutionMode %MainMesh OutputTrianglesNV
+          OpExecutionMode %MainMesh LocalSize 1 1 1
+          OpSource Slang 1
+          OpName %MainMesh "MainMesh"
+          OpDecorate %gl_Layer BuiltIn Layer
+  %void = OpTypeVoid
+     %9 = OpTypeFunction %void
+  %uint = OpTypeInt 32 0
+%uint_3 = OpConstant %uint 3
+%uint_1 = OpConstant %uint 1
+ %float = OpTypeFloat 32
+   %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+ %int_3 = OpConstant %int 3
+%uint_0 = OpConstant %uint 0
+%v3float = OpTypeVector %float 3
+%_ptr_Output_v3float = OpTypePointer Output %v3float
+%v3uint = OpTypeVector %uint 3
+%_ptr_Output_v3uint = OpTypePointer Output %v3uint
+%_ptr_Output_int = OpTypePointer Output %int
+%_arr_int_int_1 = OpTypeArray %int %int_1
+%_ptr_Output__arr_int_int_1 = OpTypePointer Output %_arr_int_int_1
+%gl_Layer = OpVariable %_ptr_Output__arr_int_int_1 Output
+%MainMesh = OpFunction %void None %9
+    %25 = OpLabel
+          OpSetMeshOutputsEXT %uint_3 %uint_1
+          OpReturn
+          OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(), AnyVUID("VUID-Layer-Layer-07039"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanBuiltinPrimitiveShadingRateKHRInBlockMeshEXT) {
+  const std::string text = R"(
+    OpCapability FragmentShadingRateKHR
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+    OpExtension "SPV_KHR_fragment_shading_rate"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 32
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_PrimitiveShadingRateEXT"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn PrimitiveShadingRateKHR
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns,
+       VulkanBuiltinPrimitiveShadingRateKHRInArrayOfIntMeshEXT) {
+  const std::string text = R"(
+      OpCapability FragmentShadingRateKHR
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+      OpExtension "SPV_KHR_fragment_shading_rate"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_PrimitiveShadingRateEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_PrimitiveShadingRateEXT "gl_PrimitiveShadingRateEXT"
+      OpDecorate %gl_PrimitiveShadingRateEXT BuiltIn PrimitiveShadingRateKHR
+      OpDecorate %gl_PrimitiveShadingRateEXT PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypePointer Output %_arr_gl_PrimitiveShadingRateEXT_uint_32
+%gl_PrimitiveShadingRateEXT = OpVariable %_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns,
+       BadVulkanBuiltinPrimitiveShadingRateKHRInArrayTypeMeshEXT) {
+  const std::string text = R"(
+      OpCapability FragmentShadingRateKHR
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+      OpExtension "SPV_KHR_fragment_shading_rate"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_PrimitiveShadingRateEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_PrimitiveShadingRateEXT "gl_PrimitiveShadingRateEXT"
+      OpDecorate %gl_PrimitiveShadingRateEXT BuiltIn PrimitiveShadingRateKHR
+      OpDecorate %gl_PrimitiveShadingRateEXT PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypeArray %bool %uint_32
+%_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypePointer Output %_arr_gl_PrimitiveShadingRateEXT_uint_32
+%gl_PrimitiveShadingRateEXT = OpVariable %_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10598"));
+}
+
+TEST_F(ValidateBuiltIns,
+       BadVulkanBuiltinPrimitiveShadingRateKHRInBlockTypeMeshEXT) {
+  const std::string text = R"(
+    OpCapability FragmentShadingRateKHR
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+    OpExtension "SPV_KHR_fragment_shading_rate"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 32
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_PrimitiveShadingRateEXT"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn PrimitiveShadingRateKHR
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10598"));
+}
+
+TEST_F(ValidateBuiltIns,
+       BadVulkanBuiltinPrimitiveShadingRateKHRInBlockSizeMeshEXT) {
+  const std::string text = R"(
+    OpCapability FragmentShadingRateKHR
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+    OpExtension "SPV_KHR_fragment_shading_rate"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 16
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_PrimitiveShadingRateEXT"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn PrimitiveShadingRateKHR
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10600"));
+}
+
+TEST_F(ValidateBuiltIns,
+       BadVulkanBuiltinPrimitiveShadingRateKHRInArraySizeMeshEXT) {
+  const std::string text = R"(
+      OpCapability FragmentShadingRateKHR
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+      OpExtension "SPV_KHR_fragment_shading_rate"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_PrimitiveShadingRateEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 16
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_PrimitiveShadingRateEXT "gl_PrimitiveShadingRateEXT"
+      OpDecorate %gl_PrimitiveShadingRateEXT BuiltIn PrimitiveShadingRateKHR
+      OpDecorate %gl_PrimitiveShadingRateEXT PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 = OpTypePointer Output %_arr_gl_PrimitiveShadingRateEXT_uint_32
+%gl_PrimitiveShadingRateEXT = OpVariable %_ptr_Output__arr_gl_PrimitiveShadingRateEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      AnyVUID("VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-10599"));
+}
+
+TEST_F(ValidateBuiltIns, VulkanBuiltinViewportIndexInBlockMeshEXT) {
+  const std::string text = R"(
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 32
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_ViewportIndex"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn ViewportIndex
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, VulkanBuiltinViewportIndexAsArrayOfIntMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_ViewportIndex
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_ViewportIndex "gl_ViewportIndex"
+      OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex
+      OpDecorate %gl_ViewportIndex PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_ViewportIndex_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_ViewportIndex_uint_32 = OpTypePointer Output %_arr_gl_ViewportIndex_uint_32
+%gl_ViewportIndex = OpVariable %_ptr_Output__arr_gl_ViewportIndex_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexInBlockTypeMeshEXT) {
+  const std::string text = R"(
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 32
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_ViewportIndex"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn ViewportIndex
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-ViewportIndex-ViewportIndex-10601"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexAsArrayTypeMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_ViewportIndex
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_ViewportIndex "gl_ViewportIndex"
+      OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex
+      OpDecorate %gl_ViewportIndex PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_ViewportIndex_uint_32 = OpTypeArray %bool %uint_32
+%_ptr_Output__arr_gl_ViewportIndex_uint_32 = OpTypePointer Output %_arr_gl_ViewportIndex_uint_32
+%gl_ViewportIndex = OpVariable %_ptr_Output__arr_gl_ViewportIndex_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-ViewportIndex-ViewportIndex-10601"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexInBlockArraySizeMeshEXT) {
+  const std::string text = R"(
+    OpCapability MeshShadingEXT
+    OpExtension "SPV_EXT_mesh_shader"
+%1 = OpExtInstImport "GLSL.std.450"
+    OpMemoryModel Logical GLSL450
+    OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+    OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+    OpExecutionMode %main OutputVertices 81
+    OpExecutionMode %main OutputPrimitivesEXT 16
+    OpExecutionMode %main OutputTrianglesEXT
+    OpSource GLSL 450
+    OpSourceExtension "GL_EXT_mesh_shader"
+    OpName %main "main"
+    OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+    OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_ViewportIndex"
+    OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+    OpDecorate %gl_MeshPerPrimitiveEXT Block
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn ViewportIndex
+    OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %int
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+%5 = OpLabel
+    OpReturn
+    OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-ViewportIndex-ViewportIndex-10603"));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexAsArrayOfIntSizeMeshEXT) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_ViewportIndex
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 16
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_ViewportIndex "gl_ViewportIndex"
+      OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex
+      OpDecorate %gl_ViewportIndex PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%_arr_gl_ViewportIndex_uint_32 = OpTypeArray %int %uint_32
+%_ptr_Output__arr_gl_ViewportIndex_uint_32 = OpTypePointer Output %_arr_gl_ViewportIndex_uint_32
+%gl_ViewportIndex = OpVariable %_ptr_Output__arr_gl_ViewportIndex_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-ViewportIndex-ViewportIndex-10602"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools