@@ -2955,9 +2955,24 @@ spv_result_t BuiltInsValidator::ValidateMeshBuiltinInterfaceRules(
29552955 const Decoration& decoration, const Instruction& inst, spv::Op scalar_type,
29562956 const Instruction& referenced_from_inst) {
29572957 if (function_id_) {
2958- if (execution_models_.count (spv::ExecutionModel::MeshEXT)) {
2958+ if (!execution_models_.count (spv::ExecutionModel::MeshEXT)) {
2959+ return SPV_SUCCESS;
2960+ }
2961+
2962+ const spv::BuiltIn builtin = decoration.builtin ();
2963+ const bool is_topology =
2964+ builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT ||
2965+ builtin == spv::BuiltIn::PrimitiveLineIndicesEXT ||
2966+ builtin == spv::BuiltIn::PrimitivePointIndicesEXT;
2967+
2968+ // These builtin have the ability to be an array with MeshEXT
2969+ // When an array, we need to make sure the array size lines up
2970+ std::map<uint32_t , uint32_t > entry_interface_id_map;
2971+ const bool is_interface_var =
2972+ IsMeshInterfaceVar (inst, entry_interface_id_map);
2973+
2974+ if (!is_topology) {
29592975 bool is_block = false ;
2960- const spv::BuiltIn builtin = decoration.builtin ();
29612976
29622977 static const std::unordered_map<spv::BuiltIn, MeshBuiltinVUIDs>
29632978 mesh_vuid_map = {{
@@ -2997,12 +3012,7 @@ spv_result_t BuiltInsValidator::ValidateMeshBuiltinInterfaceRules(
29973012 << " within the MeshEXT Execution Model must also be "
29983013 << " decorated with the PerPrimitiveEXT decoration. " ;
29993014 }
3000-
3001- // These builtin have the ability to be an array with MeshEXT
3002- // When an array, we need to make sure the array size lines up
3003- std::map<uint32_t , uint32_t > entry_interface_id_map;
3004- bool found = IsMeshInterfaceVar (inst, entry_interface_id_map);
3005- if (found) {
3015+ if (is_interface_var) {
30063016 for (const auto & id : entry_interface_id_map) {
30073017 uint32_t entry_point_id = id.first ;
30083018 uint32_t interface_var_id = id.second ;
@@ -3025,6 +3035,86 @@ spv_result_t BuiltInsValidator::ValidateMeshBuiltinInterfaceRules(
30253035 }
30263036 }
30273037 }
3038+
3039+ if (is_interface_var && is_topology) {
3040+ for (const auto & id : entry_interface_id_map) {
3041+ uint32_t entry_point_id = id.first ;
3042+
3043+ uint64_t max_output_primitives =
3044+ _.GetOutputPrimitivesEXT (entry_point_id);
3045+ uint32_t underlying_type = 0 ;
3046+ if (spv_result_t error =
3047+ GetUnderlyingType (_, decoration, inst, &underlying_type)) {
3048+ return error;
3049+ }
3050+
3051+ uint64_t primitive_array_dim = 0 ;
3052+ if (_.GetIdOpcode (underlying_type) == spv::Op::OpTypeArray) {
3053+ underlying_type = _.FindDef (underlying_type)->word (3u );
3054+ if (!_.EvalConstantValUint64 (underlying_type, &primitive_array_dim)) {
3055+ assert (0 && " Array type definition is corrupt" );
3056+ }
3057+ }
3058+
3059+ const auto * modes = _.GetExecutionModes (entry_point_id);
3060+ if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
3061+ if (!modes || !modes->count (spv::ExecutionMode::OutputTrianglesEXT)) {
3062+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3063+ << _.VkErrorID (7054 )
3064+ << " The PrimitiveTriangleIndicesEXT decoration must be used "
3065+ " with the OutputTrianglesEXT Execution Mode. " ;
3066+ }
3067+ if (primitive_array_dim &&
3068+ primitive_array_dim != max_output_primitives) {
3069+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3070+ << _.VkErrorID (7058 )
3071+ << " The size of the array decorated with "
3072+ " PrimitiveTriangleIndicesEXT ("
3073+ << primitive_array_dim
3074+ << " ) must match the value specified "
3075+ " by OutputPrimitivesEXT ("
3076+ << max_output_primitives << " ). " ;
3077+ }
3078+ } else if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
3079+ if (!modes || !modes->count (spv::ExecutionMode::OutputLinesEXT)) {
3080+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3081+ << _.VkErrorID (7048 )
3082+ << " The PrimitiveLineIndicesEXT decoration must be used "
3083+ " with the OutputLinesEXT Execution Mode. " ;
3084+ }
3085+ if (primitive_array_dim &&
3086+ primitive_array_dim != max_output_primitives) {
3087+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3088+ << _.VkErrorID (7052 )
3089+ << " The size of the array decorated with "
3090+ " PrimitiveLineIndicesEXT ("
3091+ << primitive_array_dim
3092+ << " ) must match the value specified "
3093+ " by OutputPrimitivesEXT ("
3094+ << max_output_primitives << " ). " ;
3095+ }
3096+
3097+ } else if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
3098+ if (!modes || !modes->count (spv::ExecutionMode::OutputPoints)) {
3099+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3100+ << _.VkErrorID (7042 )
3101+ << " The PrimitivePointIndicesEXT decoration must be used "
3102+ " with the OutputPoints Execution Mode. " ;
3103+ }
3104+ if (primitive_array_dim &&
3105+ primitive_array_dim != max_output_primitives) {
3106+ return _.diag (SPV_ERROR_INVALID_DATA, &inst)
3107+ << _.VkErrorID (7046 )
3108+ << " The size of the array decorated with "
3109+ " PrimitivePointIndicesEXT ("
3110+ << primitive_array_dim
3111+ << " ) must match the value specified "
3112+ " by OutputPrimitivesEXT ("
3113+ << max_output_primitives << " ). " ;
3114+ }
3115+ }
3116+ }
3117+ }
30283118 } else {
30293119 // Propagate this rule to all dependant ids in the global scope.
30303120 id_to_at_reference_checks_[referenced_from_inst.id ()].push_back (
@@ -4650,12 +4740,6 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
46504740 }
46514741 break ;
46524742 case spv::BuiltIn::CullPrimitiveEXT: {
4653- // We know this only allowed for Mesh Execution Model
4654- if (spv_result_t error = ValidateMeshBuiltinInterfaceRules (
4655- decoration, inst, spv::Op::OpTypeBool, inst)) {
4656- return error;
4657- }
4658-
46594743 for (const uint32_t entry_point : _.entry_points ()) {
46604744 auto * models = _.GetExecutionModels (entry_point);
46614745 if (models->find (spv::ExecutionModel::MeshEXT) == models->end () &&
@@ -4683,88 +4767,19 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
46834767 default :
46844768 assert (0 && " Unexpected mesh EXT builtin" );
46854769 }
4686- for (const uint32_t entry_point : _.entry_points ()) {
4687- // execution modes and builtin are both global, so only check these
4688- // buildit definitions if we know the entrypoint is Mesh
4689- auto * models = _.GetExecutionModels (entry_point);
4690- if (models->find (spv::ExecutionModel::MeshEXT) == models->end () &&
4691- models->find (spv::ExecutionModel::MeshNV) == models->end ()) {
4692- continue ;
4693- }
46944770
4695- const auto * modes = _.GetExecutionModes (entry_point);
4696- uint64_t max_output_primitives = _.GetOutputPrimitivesEXT (entry_point);
4697- uint32_t underlying_type = 0 ;
4698- if (spv_result_t error =
4699- GetUnderlyingType (_, decoration, inst, &underlying_type)) {
4700- return error;
4701- }
4702-
4703- uint64_t primitive_array_dim = 0 ;
4704- if (_.GetIdOpcode (underlying_type) == spv::Op::OpTypeArray) {
4705- underlying_type = _.FindDef (underlying_type)->word (3u );
4706- if (!_.EvalConstantValUint64 (underlying_type, &primitive_array_dim)) {
4707- assert (0 && " Array type definition is corrupt" );
4708- }
4709- }
4710- switch (builtin) {
4711- case spv::BuiltIn::PrimitivePointIndicesEXT:
4712- if (!modes || !modes->count (spv::ExecutionMode::OutputPoints)) {
4713- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4714- << _.VkErrorID (7042 )
4715- << " The PrimitivePointIndicesEXT decoration must be used "
4716- " with "
4717- " the OutputPoints Execution Mode. " ;
4718- }
4719- if (primitive_array_dim &&
4720- primitive_array_dim != max_output_primitives) {
4721- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4722- << _.VkErrorID (7046 )
4723- << " The size of the array decorated with "
4724- " PrimitivePointIndicesEXT must match the value specified "
4725- " by OutputPrimitivesEXT. " ;
4726- }
4727- break ;
4728- case spv::BuiltIn::PrimitiveLineIndicesEXT:
4729- if (!modes || !modes->count (spv::ExecutionMode::OutputLinesEXT)) {
4730- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4731- << _.VkErrorID (7048 )
4732- << " The PrimitiveLineIndicesEXT decoration must be used "
4733- " with "
4734- " the OutputLinesEXT Execution Mode. " ;
4735- }
4736- if (primitive_array_dim &&
4737- primitive_array_dim != max_output_primitives) {
4738- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4739- << _.VkErrorID (7052 )
4740- << " The size of the array decorated with "
4741- " PrimitiveLineIndicesEXT must match the value specified "
4742- " by OutputPrimitivesEXT. " ;
4743- }
4744- break ;
4745- case spv::BuiltIn::PrimitiveTriangleIndicesEXT:
4746- if (!modes || !modes->count (spv::ExecutionMode::OutputTrianglesEXT)) {
4747- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4748- << _.VkErrorID (7054 )
4749- << " The PrimitiveTriangleIndicesEXT decoration must be used "
4750- " with "
4751- " the OutputTrianglesEXT Execution Mode. " ;
4752- }
4753- if (primitive_array_dim &&
4754- primitive_array_dim != max_output_primitives) {
4755- return _.diag (SPV_ERROR_INVALID_DATA, &inst)
4756- << _.VkErrorID (7058 )
4757- << " The size of the array decorated with "
4758- " PrimitiveTriangleIndicesEXT must match the value "
4759- " specified "
4760- " by OutputPrimitivesEXT. " ;
4761- }
4762- break ;
4763- default :
4764- break ; // no validation rules
4765- }
4771+ // - We know this only allowed for Mesh Execution Model.
4772+ // - The Scalar type is is boolean for CullPrimitiveEXT, the other 3 builtin
4773+ // (topology) don't need this type.
4774+ // - It is possible to have multiple mesh
4775+ // shaders (https://github.com/KhronosGroup/SPIRV-Tools/issues/6320) and we
4776+ // need to validate these at reference time.
4777+ if (spv_result_t error = ValidateMeshBuiltinInterfaceRules (
4778+ decoration, inst, spv::Op::OpTypeBool, inst)) {
4779+ return error;
47664780 }
47674781 }
4782+
47684783 // Seed at reference checks with this built-in.
47694784 return ValidateMeshShadingEXTBuiltinsAtReference (decoration, inst, inst,
47704785 inst);
0 commit comments