Skip to content

Commit 49a8b7c

Browse files
spirv-val: Check Mesh Topology builtin by entry point (#6457)
closes #6320 Moves the Topology builtin to be done on reference, not definition
1 parent 4ba5194 commit 49a8b7c

File tree

2 files changed

+422
-93
lines changed

2 files changed

+422
-93
lines changed

source/val/validate_builtins.cpp

Lines changed: 108 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)