validate_interfaces.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. // Copyright (c) 2018 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <algorithm>
  15. #include <vector>
  16. #include "source/spirv_constant.h"
  17. #include "source/spirv_target_env.h"
  18. #include "source/val/function.h"
  19. #include "source/val/instruction.h"
  20. #include "source/val/validate.h"
  21. #include "source/val/validation_state.h"
  22. namespace spvtools {
  23. namespace val {
  24. namespace {
  25. // Limit the number of checked locations to 4096. Multiplied by 4 to represent
  26. // all the components. This limit is set to be well beyond practical use cases.
  27. const uint32_t kMaxLocations = 4096 * 4;
  28. // Returns true if \c inst is an input or output variable.
  29. bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) {
  30. if (is_spv_1_4) {
  31. // Starting in SPIR-V 1.4, all global variables are interface variables.
  32. return (inst->opcode() == spv::Op::OpVariable ||
  33. inst->opcode() == spv::Op::OpUntypedVariableKHR) &&
  34. inst->GetOperandAs<spv::StorageClass>(2u) !=
  35. spv::StorageClass::Function;
  36. } else {
  37. return (inst->opcode() == spv::Op::OpVariable ||
  38. inst->opcode() == spv::Op::OpUntypedVariableKHR) &&
  39. (inst->GetOperandAs<spv::StorageClass>(2u) ==
  40. spv::StorageClass::Input ||
  41. inst->GetOperandAs<spv::StorageClass>(2u) ==
  42. spv::StorageClass::Output);
  43. }
  44. }
  45. // Special validation for varibles that are between shader stages
  46. spv_result_t ValidateInputOutputInterfaceVariables(ValidationState_t& _,
  47. const Instruction* var) {
  48. auto var_pointer = _.FindDef(var->GetOperandAs<uint32_t>(0));
  49. uint32_t pointer_id = var_pointer->GetOperandAs<uint32_t>(2);
  50. const auto isPhysicalStorageBuffer = [](const Instruction* insn) {
  51. return insn->opcode() == spv::Op::OpTypePointer &&
  52. insn->GetOperandAs<spv::StorageClass>(1) ==
  53. spv::StorageClass::PhysicalStorageBuffer;
  54. };
  55. if (_.ContainsType(pointer_id, isPhysicalStorageBuffer)) {
  56. return _.diag(SPV_ERROR_INVALID_ID, var)
  57. << _.VkErrorID(9557) << "Input/Output interface variable id <"
  58. << var->id()
  59. << "> contains a PhysicalStorageBuffer pointer, which is not "
  60. "allowed. If you want to interface shader stages with a "
  61. "PhysicalStorageBuffer, cast to a uint64 or uvec2 instead.";
  62. }
  63. return SPV_SUCCESS;
  64. }
  65. // Checks that \c var is listed as an interface in all the entry points that use
  66. // it.
  67. spv_result_t check_interface_variable(ValidationState_t& _,
  68. const Instruction* var) {
  69. std::vector<const Function*> functions;
  70. std::vector<const Instruction*> uses;
  71. for (auto use : var->uses()) {
  72. uses.push_back(use.first);
  73. }
  74. for (uint32_t i = 0; i < uses.size(); ++i) {
  75. const auto user = uses[i];
  76. if (const Function* func = user->function()) {
  77. functions.push_back(func);
  78. } else {
  79. // In the rare case that the variable is used by another instruction in
  80. // the global scope, continue searching for an instruction used in a
  81. // function.
  82. for (auto use : user->uses()) {
  83. uses.push_back(use.first);
  84. }
  85. }
  86. }
  87. std::sort(functions.begin(), functions.end(),
  88. [](const Function* lhs, const Function* rhs) {
  89. return lhs->id() < rhs->id();
  90. });
  91. functions.erase(std::unique(functions.begin(), functions.end()),
  92. functions.end());
  93. std::vector<uint32_t> entry_points;
  94. for (const auto func : functions) {
  95. for (auto id : _.FunctionEntryPoints(func->id())) {
  96. entry_points.push_back(id);
  97. }
  98. }
  99. std::sort(entry_points.begin(), entry_points.end());
  100. entry_points.erase(std::unique(entry_points.begin(), entry_points.end()),
  101. entry_points.end());
  102. for (auto id : entry_points) {
  103. for (const auto& desc : _.entry_point_descriptions(id)) {
  104. bool found = false;
  105. for (auto interface : desc.interfaces) {
  106. if (var->id() == interface) {
  107. found = true;
  108. break;
  109. }
  110. }
  111. if (!found) {
  112. return _.diag(SPV_ERROR_INVALID_ID, var)
  113. << "Interface variable id <" << var->id()
  114. << "> is used by entry point '" << desc.name << "' id <" << id
  115. << ">, but is not listed as an interface";
  116. }
  117. }
  118. }
  119. if (var->GetOperandAs<spv::StorageClass>(2) == spv::StorageClass::Input ||
  120. var->GetOperandAs<spv::StorageClass>(2) == spv::StorageClass::Output) {
  121. if (auto error = ValidateInputOutputInterfaceVariables(_, var))
  122. return error;
  123. }
  124. return SPV_SUCCESS;
  125. }
  126. // This function assumes a base location has been determined already. As such
  127. // any further location decorations are invalid.
  128. // TODO: if this code turns out to be slow, there is an opportunity to cache
  129. // the result for a given type id.
  130. spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type,
  131. uint32_t* num_locations) {
  132. *num_locations = 0;
  133. switch (type->opcode()) {
  134. case spv::Op::OpTypeInt:
  135. case spv::Op::OpTypeFloat:
  136. // Scalars always consume a single location.
  137. *num_locations = 1;
  138. break;
  139. case spv::Op::OpTypeVector:
  140. // 3- and 4-component 64-bit vectors consume two locations.
  141. if ((_.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeInt, 64) ||
  142. _.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeFloat,
  143. 64)) &&
  144. (type->GetOperandAs<uint32_t>(2) > 2)) {
  145. *num_locations = 2;
  146. } else {
  147. *num_locations = 1;
  148. }
  149. break;
  150. case spv::Op::OpTypeMatrix:
  151. // Matrices consume locations equivalent to arrays of 4-component vectors.
  152. if (_.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeInt, 64) ||
  153. _.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeFloat, 64)) {
  154. *num_locations = 2;
  155. } else {
  156. *num_locations = 1;
  157. }
  158. *num_locations *= type->GetOperandAs<uint32_t>(2);
  159. break;
  160. case spv::Op::OpTypeArray: {
  161. // Arrays consume locations equal to the underlying type times the number
  162. // of elements in the vector.
  163. if (auto error = NumConsumedLocations(
  164. _, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
  165. return error;
  166. }
  167. bool is_int = false;
  168. bool is_const = false;
  169. uint32_t value = 0;
  170. // Attempt to evaluate the number of array elements.
  171. std::tie(is_int, is_const, value) =
  172. _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
  173. if (is_int && is_const) *num_locations *= value;
  174. break;
  175. }
  176. case spv::Op::OpTypeStruct: {
  177. // Members cannot have location decorations at this point.
  178. if (_.HasDecoration(type->id(), spv::Decoration::Location)) {
  179. return _.diag(SPV_ERROR_INVALID_DATA, type)
  180. << _.VkErrorID(4918) << "Members cannot be assigned a location";
  181. }
  182. // Structs consume locations equal to the sum of the locations consumed
  183. // by the members.
  184. for (uint32_t i = 1; i < type->operands().size(); ++i) {
  185. uint32_t member_locations = 0;
  186. if (auto error = NumConsumedLocations(
  187. _, _.FindDef(type->GetOperandAs<uint32_t>(i)),
  188. &member_locations)) {
  189. return error;
  190. }
  191. *num_locations += member_locations;
  192. }
  193. break;
  194. }
  195. case spv::Op::OpTypePointer: {
  196. if (_.addressing_model() ==
  197. spv::AddressingModel::PhysicalStorageBuffer64 &&
  198. type->GetOperandAs<spv::StorageClass>(1) ==
  199. spv::StorageClass::PhysicalStorageBuffer) {
  200. *num_locations = 1;
  201. break;
  202. }
  203. [[fallthrough]];
  204. }
  205. default:
  206. return _.diag(SPV_ERROR_INVALID_DATA, type)
  207. << "Invalid type to assign a location";
  208. }
  209. return SPV_SUCCESS;
  210. }
  211. // Returns the number of components consumed by types that support a component
  212. // decoration.
  213. uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) {
  214. uint32_t num_components = 0;
  215. switch (type->opcode()) {
  216. case spv::Op::OpTypeInt:
  217. case spv::Op::OpTypeFloat:
  218. // 64-bit types consume two components.
  219. if (type->GetOperandAs<uint32_t>(1) == 64) {
  220. num_components = 2;
  221. } else {
  222. num_components = 1;
  223. }
  224. break;
  225. case spv::Op::OpTypeVector:
  226. // Vectors consume components equal to the underlying type's consumption
  227. // times the number of elements in the vector. Note that 3- and 4-element
  228. // vectors cannot have a component decoration (i.e. assumed to be zero).
  229. num_components =
  230. NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
  231. num_components *= type->GetOperandAs<uint32_t>(2);
  232. break;
  233. case spv::Op::OpTypeMatrix:
  234. // Matrices consume all components of the location.
  235. // Round up to next multiple of 4.
  236. num_components =
  237. NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
  238. num_components *= type->GetOperandAs<uint32_t>(2);
  239. num_components = ((num_components + 3) / 4) * 4;
  240. break;
  241. case spv::Op::OpTypeArray: {
  242. // Arrays consume all components of the location.
  243. // Round up to next multiple of 4.
  244. num_components =
  245. NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
  246. bool is_int = false;
  247. bool is_const = false;
  248. uint32_t value = 0;
  249. // Attempt to evaluate the number of array elements.
  250. std::tie(is_int, is_const, value) =
  251. _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
  252. if (is_int && is_const) num_components *= value;
  253. num_components = ((num_components + 3) / 4) * 4;
  254. return num_components;
  255. }
  256. case spv::Op::OpTypePointer:
  257. if (_.addressing_model() ==
  258. spv::AddressingModel::PhysicalStorageBuffer64 &&
  259. type->GetOperandAs<spv::StorageClass>(1) ==
  260. spv::StorageClass::PhysicalStorageBuffer) {
  261. return 2;
  262. }
  263. break;
  264. default:
  265. // This is an error that is validated elsewhere.
  266. break;
  267. }
  268. return num_components;
  269. }
  270. // Populates |locations| (and/or |output_index1_locations|) with the use
  271. // location and component coordinates for |variable|. Indices are calculated as
  272. // 4 * location + component.
  273. spv_result_t GetLocationsForVariable(
  274. ValidationState_t& _, const Instruction* entry_point,
  275. const Instruction* variable, std::unordered_set<uint32_t>* locations,
  276. std::unordered_set<uint32_t>* output_index1_locations) {
  277. const bool is_fragment = entry_point->GetOperandAs<spv::ExecutionModel>(0) ==
  278. spv::ExecutionModel::Fragment;
  279. const auto sc_index = 2u;
  280. const bool is_output = variable->GetOperandAs<spv::StorageClass>(sc_index) ==
  281. spv::StorageClass::Output;
  282. auto ptr_type_id = variable->GetOperandAs<uint32_t>(0);
  283. auto ptr_type = _.FindDef(ptr_type_id);
  284. auto type_id = ptr_type->GetOperandAs<uint32_t>(2);
  285. auto type = _.FindDef(type_id);
  286. // Check for Location, Component and Index decorations on the variable. The
  287. // validator allows duplicate decorations if the location/component/index are
  288. // equal. Also track Patch and PerTaskNV decorations.
  289. bool has_location = false;
  290. uint32_t location = 0;
  291. uint32_t component = 0;
  292. bool has_index = false;
  293. uint32_t index = 0;
  294. bool has_patch = false;
  295. bool has_per_task_nv = false;
  296. bool has_per_vertex_khr = false;
  297. // Duplicate Location, Component, Index are checked elsewhere.
  298. for (auto& dec : _.id_decorations(variable->id())) {
  299. if (dec.dec_type() == spv::Decoration::Location) {
  300. has_location = true;
  301. location = dec.params()[0];
  302. } else if (dec.dec_type() == spv::Decoration::Component) {
  303. component = dec.params()[0];
  304. } else if (dec.dec_type() == spv::Decoration::Index) {
  305. if (!is_output || !is_fragment) {
  306. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  307. << "Index can only be applied to Fragment output variables";
  308. }
  309. has_index = true;
  310. index = dec.params()[0];
  311. } else if (dec.dec_type() == spv::Decoration::BuiltIn) {
  312. // Don't check built-ins.
  313. return SPV_SUCCESS;
  314. } else if (dec.dec_type() == spv::Decoration::Patch) {
  315. has_patch = true;
  316. } else if (dec.dec_type() == spv::Decoration::PerTaskNV) {
  317. has_per_task_nv = true;
  318. } else if (dec.dec_type() == spv::Decoration::PerVertexKHR) {
  319. if (!is_fragment) {
  320. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  321. << _.VkErrorID(6777)
  322. << "PerVertexKHR can only be applied to Fragment Execution "
  323. "Models";
  324. }
  325. if (type->opcode() != spv::Op::OpTypeArray &&
  326. type->opcode() != spv::Op::OpTypeRuntimeArray) {
  327. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  328. << _.VkErrorID(6778)
  329. << "PerVertexKHR must be declared as arrays";
  330. }
  331. has_per_vertex_khr = true;
  332. }
  333. }
  334. // Vulkan 15.1.3 (Interface Matching): Tessellation control and mesh
  335. // per-vertex outputs and tessellation control, evaluation and geometry
  336. // per-vertex inputs have a layer of arraying that is not included in
  337. // interface matching.
  338. bool is_arrayed = false;
  339. switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
  340. case spv::ExecutionModel::TessellationControl:
  341. if (!has_patch) {
  342. is_arrayed = true;
  343. }
  344. break;
  345. case spv::ExecutionModel::TessellationEvaluation:
  346. if (!is_output && !has_patch) {
  347. is_arrayed = true;
  348. }
  349. break;
  350. case spv::ExecutionModel::Geometry:
  351. if (!is_output) {
  352. is_arrayed = true;
  353. }
  354. break;
  355. case spv::ExecutionModel::Fragment:
  356. if (!is_output && has_per_vertex_khr) {
  357. is_arrayed = true;
  358. }
  359. break;
  360. case spv::ExecutionModel::MeshNV:
  361. if (is_output && !has_per_task_nv) {
  362. is_arrayed = true;
  363. }
  364. break;
  365. default:
  366. break;
  367. }
  368. // Unpack arrayness.
  369. if (is_arrayed && (type->opcode() == spv::Op::OpTypeArray ||
  370. type->opcode() == spv::Op::OpTypeRuntimeArray)) {
  371. type_id = type->GetOperandAs<uint32_t>(1);
  372. type = _.FindDef(type_id);
  373. }
  374. if (type->opcode() == spv::Op::OpTypeStruct) {
  375. // Don't check built-ins.
  376. if (_.HasDecoration(type_id, spv::Decoration::BuiltIn)) return SPV_SUCCESS;
  377. }
  378. // Only block-decorated structs don't need a location on the variable.
  379. const bool is_block = _.HasDecoration(type_id, spv::Decoration::Block);
  380. if (!has_location && !is_block) {
  381. const auto vuid = (type->opcode() == spv::Op::OpTypeStruct) ? 4917 : 4916;
  382. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  383. << _.VkErrorID(vuid) << "Variable must be decorated with a location";
  384. }
  385. const std::string storage_class = is_output ? "output" : "input";
  386. if (has_location) {
  387. uint32_t num_locations = 0;
  388. if (auto error = NumConsumedLocations(_, type, &num_locations))
  389. return error;
  390. uint32_t num_components = NumConsumedComponents(_, type);
  391. uint32_t start = location * 4;
  392. uint32_t end = (location + num_locations) * 4;
  393. if (num_components % 4 != 0) {
  394. start += component;
  395. end = start + num_components;
  396. }
  397. if (kMaxLocations <= start) {
  398. // Too many locations, give up.
  399. return SPV_SUCCESS;
  400. }
  401. auto locs = locations;
  402. if (has_index && index == 1) locs = output_index1_locations;
  403. for (uint32_t i = start; i < end; ++i) {
  404. if (!locs->insert(i).second) {
  405. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  406. << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
  407. << "Entry-point has conflicting " << storage_class
  408. << " location assignment at location " << i / 4 << ", component "
  409. << i % 4;
  410. }
  411. }
  412. } else {
  413. // For Block-decorated structs with no location assigned to the variable,
  414. // each member of the block must be assigned a location. Also record any
  415. // member component assignments. The validator allows duplicate decorations
  416. // if they agree on the location/component.
  417. std::unordered_map<uint32_t, uint32_t> member_locations;
  418. std::unordered_map<uint32_t, uint32_t> member_components;
  419. for (auto& dec : _.id_decorations(type_id)) {
  420. if (dec.dec_type() == spv::Decoration::Location) {
  421. auto where = member_locations.find(dec.struct_member_index());
  422. if (where == member_locations.end()) {
  423. member_locations[dec.struct_member_index()] = dec.params()[0];
  424. } else if (where->second != dec.params()[0]) {
  425. return _.diag(SPV_ERROR_INVALID_DATA, type)
  426. << "Member index " << dec.struct_member_index()
  427. << " has conflicting location assignments";
  428. }
  429. } else if (dec.dec_type() == spv::Decoration::Component) {
  430. auto where = member_components.find(dec.struct_member_index());
  431. if (where == member_components.end()) {
  432. member_components[dec.struct_member_index()] = dec.params()[0];
  433. } else if (where->second != dec.params()[0]) {
  434. return _.diag(SPV_ERROR_INVALID_DATA, type)
  435. << "Member index " << dec.struct_member_index()
  436. << " has conflicting component assignments";
  437. }
  438. }
  439. }
  440. for (uint32_t i = 1; i < type->operands().size(); ++i) {
  441. auto where = member_locations.find(i - 1);
  442. if (where == member_locations.end()) {
  443. return _.diag(SPV_ERROR_INVALID_DATA, type)
  444. << _.VkErrorID(4919) << "Member index " << i - 1
  445. << " is missing a location assignment";
  446. }
  447. location = where->second;
  448. auto member = _.FindDef(type->GetOperandAs<uint32_t>(i));
  449. uint32_t num_locations = 0;
  450. if (auto error = NumConsumedLocations(_, member, &num_locations))
  451. return error;
  452. // If the component is not specified, it is assumed to be zero.
  453. uint32_t num_components = NumConsumedComponents(_, member);
  454. component = 0;
  455. if (member_components.count(i - 1)) {
  456. component = member_components[i - 1];
  457. }
  458. uint32_t start = location * 4;
  459. if (kMaxLocations <= start) {
  460. // Too many locations, give up.
  461. continue;
  462. }
  463. uint32_t end = (location + num_locations) * 4;
  464. if (num_components % 4 != 0) {
  465. start += component;
  466. end = location * 4 + component + num_components;
  467. }
  468. for (uint32_t l = start; l < end; ++l) {
  469. if (!locations->insert(l).second) {
  470. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  471. << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
  472. << "Entry-point has conflicting " << storage_class
  473. << " location assignment at location " << l / 4
  474. << ", component " << l % 4;
  475. }
  476. }
  477. }
  478. }
  479. return SPV_SUCCESS;
  480. }
  481. spv_result_t ValidateLocations(ValidationState_t& _,
  482. const Instruction* entry_point) {
  483. // According to Vulkan 14.1 only the following execution models have
  484. // locations assigned.
  485. // TODO(dneto): SPV_NV_ray_tracing also uses locations on interface variables,
  486. // in other shader stages. Similarly, the *provisional* version of
  487. // SPV_KHR_ray_tracing did as well, but not the final version.
  488. switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
  489. case spv::ExecutionModel::Vertex:
  490. case spv::ExecutionModel::TessellationControl:
  491. case spv::ExecutionModel::TessellationEvaluation:
  492. case spv::ExecutionModel::Geometry:
  493. case spv::ExecutionModel::Fragment:
  494. break;
  495. default:
  496. return SPV_SUCCESS;
  497. }
  498. // Locations are stored as a combined location and component values.
  499. std::unordered_set<uint32_t> input_locations;
  500. std::unordered_set<uint32_t> output_locations_index0;
  501. std::unordered_set<uint32_t> output_locations_index1;
  502. std::unordered_set<uint32_t> patch_locations_index0;
  503. std::unordered_set<uint32_t> patch_locations_index1;
  504. std::unordered_set<uint32_t> seen;
  505. for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
  506. auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
  507. auto interface_var = _.FindDef(interface_id);
  508. const auto sc_index = 2u;
  509. auto storage_class =
  510. interface_var->GetOperandAs<spv::StorageClass>(sc_index);
  511. if (storage_class != spv::StorageClass::Input &&
  512. storage_class != spv::StorageClass::Output) {
  513. continue;
  514. }
  515. if (!seen.insert(interface_id).second) {
  516. // Pre-1.4 an interface variable could be listed multiple times in an
  517. // entry point. Validation for 1.4 or later is done elsewhere.
  518. continue;
  519. }
  520. // The two Tessellation stages have a "Patch" variable that interface with
  521. // the Location mechanism, but are not suppose to be tied to the "normal"
  522. // input/output Location.
  523. // TODO - SPIR-V allows the Patch decoration to be applied to struct
  524. // members, but is not allowed in GLSL/HLSL
  525. bool has_patch = false;
  526. for (auto& dec : _.id_decorations(interface_var->id())) {
  527. if (dec.dec_type() == spv::Decoration::Patch) {
  528. has_patch = true;
  529. if (auto error = GetLocationsForVariable(_, entry_point, interface_var,
  530. &patch_locations_index0,
  531. &patch_locations_index1))
  532. return error;
  533. break;
  534. }
  535. }
  536. if (has_patch) {
  537. continue;
  538. }
  539. auto locations = (storage_class == spv::StorageClass::Input)
  540. ? &input_locations
  541. : &output_locations_index0;
  542. if (auto error = GetLocationsForVariable(
  543. _, entry_point, interface_var, locations, &output_locations_index1))
  544. return error;
  545. }
  546. return SPV_SUCCESS;
  547. }
  548. spv_result_t ValidateStorageClass(ValidationState_t& _,
  549. const Instruction* entry_point) {
  550. bool has_push_constant = false;
  551. bool has_ray_payload = false;
  552. bool has_hit_attribute = false;
  553. bool has_callable_data = false;
  554. for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
  555. auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
  556. auto interface_var = _.FindDef(interface_id);
  557. auto storage_class = interface_var->GetOperandAs<spv::StorageClass>(2);
  558. switch (storage_class) {
  559. case spv::StorageClass::PushConstant: {
  560. if (has_push_constant) {
  561. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  562. << _.VkErrorID(6673)
  563. << "Entry-point has more than one variable with the "
  564. "PushConstant storage class in the interface";
  565. }
  566. has_push_constant = true;
  567. break;
  568. }
  569. case spv::StorageClass::IncomingRayPayloadKHR: {
  570. if (has_ray_payload) {
  571. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  572. << _.VkErrorID(4700)
  573. << "Entry-point has more than one variable with the "
  574. "IncomingRayPayloadKHR storage class in the interface";
  575. }
  576. has_ray_payload = true;
  577. break;
  578. }
  579. case spv::StorageClass::HitAttributeKHR: {
  580. if (has_hit_attribute) {
  581. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  582. << _.VkErrorID(4702)
  583. << "Entry-point has more than one variable with the "
  584. "HitAttributeKHR storage class in the interface";
  585. }
  586. has_hit_attribute = true;
  587. break;
  588. }
  589. case spv::StorageClass::IncomingCallableDataKHR: {
  590. if (has_callable_data) {
  591. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  592. << _.VkErrorID(4706)
  593. << "Entry-point has more than one variable with the "
  594. "IncomingCallableDataKHR storage class in the interface";
  595. }
  596. has_callable_data = true;
  597. break;
  598. }
  599. default:
  600. break;
  601. }
  602. }
  603. return SPV_SUCCESS;
  604. }
  605. } // namespace
  606. spv_result_t ValidateInterfaces(ValidationState_t& _) {
  607. bool is_spv_1_4 = _.version() >= SPV_SPIRV_VERSION_WORD(1, 4);
  608. for (auto& inst : _.ordered_instructions()) {
  609. if (is_interface_variable(&inst, is_spv_1_4)) {
  610. if (auto error = check_interface_variable(_, &inst)) {
  611. return error;
  612. }
  613. }
  614. }
  615. if (spvIsVulkanEnv(_.context()->target_env)) {
  616. for (auto& inst : _.ordered_instructions()) {
  617. if (inst.opcode() == spv::Op::OpEntryPoint) {
  618. if (auto error = ValidateLocations(_, &inst)) {
  619. return error;
  620. }
  621. if (auto error = ValidateStorageClass(_, &inst)) {
  622. return error;
  623. }
  624. }
  625. if (inst.opcode() == spv::Op::OpTypeVoid) break;
  626. }
  627. }
  628. return SPV_SUCCESS;
  629. }
  630. } // namespace val
  631. } // namespace spvtools