Populates |locations| (and/or |output_index1_locations|) with the use location and component coordinates for |variable|. Indices are calculated as 4 * location + component.
| 272 | // location and component coordinates for |variable|. Indices are calculated as |
| 273 | // 4 * location + component. |
| 274 | spv_result_t GetLocationsForVariable( |
| 275 | ValidationState_t& _, const Instruction* entry_point, |
| 276 | const Instruction* variable, std::unordered_set<uint32_t>* locations, |
| 277 | std::unordered_set<uint32_t>* output_index1_locations) { |
| 278 | const bool is_fragment = entry_point->GetOperandAs<spv::ExecutionModel>(0) == |
| 279 | spv::ExecutionModel::Fragment; |
| 280 | const auto sc_index = 2u; |
| 281 | const bool is_output = variable->GetOperandAs<spv::StorageClass>(sc_index) == |
| 282 | spv::StorageClass::Output; |
| 283 | auto ptr_type_id = variable->GetOperandAs<uint32_t>(0); |
| 284 | auto ptr_type = _.FindDef(ptr_type_id); |
| 285 | auto type_id = ptr_type->GetOperandAs<uint32_t>(2); |
| 286 | auto type = _.FindDef(type_id); |
| 287 | |
| 288 | // Check for Location, Component and Index decorations on the variable. The |
| 289 | // validator allows duplicate decorations if the location/component/index are |
| 290 | // equal. Also track Patch and PerTaskNV decorations. |
| 291 | bool has_location = false; |
| 292 | uint32_t location = 0; |
| 293 | uint32_t component = 0; |
| 294 | bool has_index = false; |
| 295 | uint32_t index = 0; |
| 296 | bool has_patch = false; |
| 297 | bool has_per_task_nv = false; |
| 298 | bool has_per_vertex_khr = false; |
| 299 | // Duplicate Location, Component, Index are checked elsewhere. |
| 300 | for (auto& dec : _.id_decorations(variable->id())) { |
| 301 | if (dec.dec_type() == spv::Decoration::Location) { |
| 302 | has_location = true; |
| 303 | location = dec.params()[0]; |
| 304 | } else if (dec.dec_type() == spv::Decoration::Component) { |
| 305 | component = dec.params()[0]; |
| 306 | } else if (dec.dec_type() == spv::Decoration::Index) { |
| 307 | if (!is_output || !is_fragment) { |
| 308 | return _.diag(SPV_ERROR_INVALID_DATA, variable) |
| 309 | << "Index can only be applied to Fragment output variables"; |
| 310 | } |
| 311 | has_index = true; |
| 312 | index = dec.params()[0]; |
| 313 | } else if (dec.dec_type() == spv::Decoration::BuiltIn) { |
| 314 | // Don't check built-ins. |
| 315 | return SPV_SUCCESS; |
| 316 | } else if (dec.dec_type() == spv::Decoration::Patch) { |
| 317 | has_patch = true; |
| 318 | } else if (dec.dec_type() == spv::Decoration::PerTaskNV) { |
| 319 | has_per_task_nv = true; |
| 320 | } else if (dec.dec_type() == spv::Decoration::PerVertexKHR) { |
| 321 | if (!is_fragment) { |
| 322 | return _.diag(SPV_ERROR_INVALID_DATA, variable) |
| 323 | << _.VkErrorID(6777) |
| 324 | << "PerVertexKHR can only be applied to Fragment Execution " |
| 325 | "Models"; |
| 326 | } |
| 327 | if (type->opcode() != spv::Op::OpTypeArray && |
| 328 | type->opcode() != spv::Op::OpTypeRuntimeArray) { |
| 329 | return _.diag(SPV_ERROR_INVALID_DATA, variable) |
| 330 | << _.VkErrorID(6778) |
| 331 | << "PerVertexKHR must be declared as arrays"; |
no test coverage detected