| 534 | } |
| 535 | |
| 536 | spv_result_t ValidateLocations(ValidationState_t& _, |
| 537 | const Instruction* entry_point) { |
| 538 | // According to Vulkan 14.1 only the following execution models have |
| 539 | // locations assigned. |
| 540 | // TODO(dneto): SPV_NV_ray_tracing also uses locations on interface variables, |
| 541 | // in other shader stages. Similarly, the *provisional* version of |
| 542 | // SPV_KHR_ray_tracing did as well, but not the final version. |
| 543 | switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) { |
| 544 | case spv::ExecutionModel::Vertex: |
| 545 | case spv::ExecutionModel::TessellationControl: |
| 546 | case spv::ExecutionModel::TessellationEvaluation: |
| 547 | case spv::ExecutionModel::Geometry: |
| 548 | case spv::ExecutionModel::Fragment: |
| 549 | break; |
| 550 | default: |
| 551 | return SPV_SUCCESS; |
| 552 | } |
| 553 | |
| 554 | const bool is_geometry = entry_point->GetOperandAs<spv::ExecutionModel>(0) == |
| 555 | spv::ExecutionModel::Geometry; |
| 556 | const bool has_geometry_streams = |
| 557 | is_geometry && _.HasCapability(spv::Capability::GeometryStreams); |
| 558 | |
| 559 | // Locations are stored as a combined location and component values. |
| 560 | std::unordered_set<uint32_t> input_locations; |
| 561 | std::unordered_set<uint32_t> output_locations_index0; |
| 562 | std::unordered_set<uint32_t> output_locations_index1; |
| 563 | std::unordered_set<uint32_t> patch_locations_index0; |
| 564 | std::unordered_set<uint32_t> patch_locations_index1; |
| 565 | std::unordered_map<uint32_t, std::unordered_set<uint32_t>> |
| 566 | output_locations_per_stream; |
| 567 | std::unordered_map<uint32_t, std::unordered_set<uint32_t>> |
| 568 | output_index1_locations_per_stream; |
| 569 | std::unordered_set<uint32_t> seen; |
| 570 | for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { |
| 571 | auto interface_id = entry_point->GetOperandAs<uint32_t>(i); |
| 572 | auto interface_var = _.FindDef(interface_id); |
| 573 | const auto sc_index = 2u; |
| 574 | auto storage_class = |
| 575 | interface_var->GetOperandAs<spv::StorageClass>(sc_index); |
| 576 | if (storage_class != spv::StorageClass::Input && |
| 577 | storage_class != spv::StorageClass::Output) { |
| 578 | continue; |
| 579 | } |
| 580 | if (!seen.insert(interface_id).second) { |
| 581 | // Pre-1.4 an interface variable could be listed multiple times in an |
| 582 | // entry point. Validation for 1.4 or later is done elsewhere. |
| 583 | continue; |
| 584 | } |
| 585 | |
| 586 | // The two Tessellation stages have a "Patch" variable that interface with |
| 587 | // the Location mechanism, but are not suppose to be tied to the "normal" |
| 588 | // input/output Location. |
| 589 | // TODO - SPIR-V allows the Patch decoration to be applied to struct |
| 590 | // members, but is not allowed in GLSL/HLSL |
| 591 | bool has_patch = false; |
| 592 | for (auto& dec : _.id_decorations(interface_var->id())) { |
| 593 | if (dec.dec_type() == spv::Decoration::Patch) { |
no test coverage detected