validate_mode_setting.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. //
  15. #include <algorithm>
  16. #include "source/opcode.h"
  17. #include "source/spirv_target_env.h"
  18. #include "source/val/instruction.h"
  19. #include "source/val/validate.h"
  20. #include "source/val/validation_state.h"
  21. namespace spvtools {
  22. namespace val {
  23. namespace {
  24. spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
  25. const auto entry_point_id = inst->GetOperandAs<uint32_t>(1);
  26. auto entry_point = _.FindDef(entry_point_id);
  27. if (!entry_point || spv::Op::OpFunction != entry_point->opcode()) {
  28. return _.diag(SPV_ERROR_INVALID_ID, inst)
  29. << "OpEntryPoint Entry Point <id> " << _.getIdName(entry_point_id)
  30. << " is not a function.";
  31. }
  32. // Only check the shader execution models
  33. const spv::ExecutionModel execution_model =
  34. inst->GetOperandAs<spv::ExecutionModel>(0);
  35. if (execution_model != spv::ExecutionModel::Kernel) {
  36. const auto entry_point_type_id = entry_point->GetOperandAs<uint32_t>(3);
  37. const auto entry_point_type = _.FindDef(entry_point_type_id);
  38. if (!entry_point_type || 3 != entry_point_type->words().size()) {
  39. return _.diag(SPV_ERROR_INVALID_ID, inst)
  40. << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> "
  41. << _.getIdName(entry_point_id)
  42. << "s function parameter count is not zero.";
  43. }
  44. }
  45. auto return_type = _.FindDef(entry_point->type_id());
  46. if (!return_type || spv::Op::OpTypeVoid != return_type->opcode()) {
  47. return _.diag(SPV_ERROR_INVALID_ID, inst)
  48. << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> "
  49. << _.getIdName(entry_point_id)
  50. << "s function return type is not void.";
  51. }
  52. const auto* execution_modes = _.GetExecutionModes(entry_point_id);
  53. if (_.HasCapability(spv::Capability::Shader)) {
  54. switch (execution_model) {
  55. case spv::ExecutionModel::Fragment:
  56. if (execution_modes &&
  57. execution_modes->count(spv::ExecutionMode::OriginUpperLeft) &&
  58. execution_modes->count(spv::ExecutionMode::OriginLowerLeft)) {
  59. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  60. << "Fragment execution model entry points can only specify "
  61. "one of OriginUpperLeft or OriginLowerLeft execution "
  62. "modes.";
  63. }
  64. if (!execution_modes ||
  65. (!execution_modes->count(spv::ExecutionMode::OriginUpperLeft) &&
  66. !execution_modes->count(spv::ExecutionMode::OriginLowerLeft))) {
  67. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  68. << "Fragment execution model entry points require either an "
  69. "OriginUpperLeft or OriginLowerLeft execution mode.";
  70. }
  71. if (execution_modes &&
  72. 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
  73. [](const spv::ExecutionMode& mode) {
  74. switch (mode) {
  75. case spv::ExecutionMode::DepthGreater:
  76. case spv::ExecutionMode::DepthLess:
  77. case spv::ExecutionMode::DepthUnchanged:
  78. return true;
  79. default:
  80. return false;
  81. }
  82. })) {
  83. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  84. << "Fragment execution model entry points can specify at most "
  85. "one of DepthGreater, DepthLess or DepthUnchanged "
  86. "execution modes.";
  87. }
  88. if (execution_modes &&
  89. 1 < std::count_if(
  90. execution_modes->begin(), execution_modes->end(),
  91. [](const spv::ExecutionMode& mode) {
  92. switch (mode) {
  93. case spv::ExecutionMode::PixelInterlockOrderedEXT:
  94. case spv::ExecutionMode::PixelInterlockUnorderedEXT:
  95. case spv::ExecutionMode::SampleInterlockOrderedEXT:
  96. case spv::ExecutionMode::SampleInterlockUnorderedEXT:
  97. case spv::ExecutionMode::ShadingRateInterlockOrderedEXT:
  98. case spv::ExecutionMode::
  99. ShadingRateInterlockUnorderedEXT:
  100. return true;
  101. default:
  102. return false;
  103. }
  104. })) {
  105. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  106. << "Fragment execution model entry points can specify at most "
  107. "one fragment shader interlock execution mode.";
  108. }
  109. if (execution_modes &&
  110. 1 < std::count_if(
  111. execution_modes->begin(), execution_modes->end(),
  112. [](const spv::ExecutionMode& mode) {
  113. switch (mode) {
  114. case spv::ExecutionMode::StencilRefUnchangedFrontAMD:
  115. case spv::ExecutionMode::StencilRefLessFrontAMD:
  116. case spv::ExecutionMode::StencilRefGreaterFrontAMD:
  117. return true;
  118. default:
  119. return false;
  120. }
  121. })) {
  122. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  123. << "Fragment execution model entry points can specify at most "
  124. "one of StencilRefUnchangedFrontAMD, "
  125. "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
  126. "execution modes.";
  127. }
  128. if (execution_modes &&
  129. 1 < std::count_if(
  130. execution_modes->begin(), execution_modes->end(),
  131. [](const spv::ExecutionMode& mode) {
  132. switch (mode) {
  133. case spv::ExecutionMode::StencilRefUnchangedBackAMD:
  134. case spv::ExecutionMode::StencilRefLessBackAMD:
  135. case spv::ExecutionMode::StencilRefGreaterBackAMD:
  136. return true;
  137. default:
  138. return false;
  139. }
  140. })) {
  141. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  142. << "Fragment execution model entry points can specify at most "
  143. "one of StencilRefUnchangedBackAMD, "
  144. "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
  145. "execution modes.";
  146. }
  147. break;
  148. case spv::ExecutionModel::TessellationControl:
  149. case spv::ExecutionModel::TessellationEvaluation:
  150. if (execution_modes &&
  151. 1 < std::count_if(
  152. execution_modes->begin(), execution_modes->end(),
  153. [](const spv::ExecutionMode& mode) {
  154. switch (mode) {
  155. case spv::ExecutionMode::SpacingEqual:
  156. case spv::ExecutionMode::SpacingFractionalEven:
  157. case spv::ExecutionMode::SpacingFractionalOdd:
  158. return true;
  159. default:
  160. return false;
  161. }
  162. })) {
  163. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  164. << "Tessellation execution model entry points can specify at "
  165. "most one of SpacingEqual, SpacingFractionalOdd or "
  166. "SpacingFractionalEven execution modes.";
  167. }
  168. if (execution_modes &&
  169. 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
  170. [](const spv::ExecutionMode& mode) {
  171. switch (mode) {
  172. case spv::ExecutionMode::Triangles:
  173. case spv::ExecutionMode::Quads:
  174. case spv::ExecutionMode::Isolines:
  175. return true;
  176. default:
  177. return false;
  178. }
  179. })) {
  180. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  181. << "Tessellation execution model entry points can specify at "
  182. "most one of Triangles, Quads or Isolines execution modes.";
  183. }
  184. if (execution_modes &&
  185. 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
  186. [](const spv::ExecutionMode& mode) {
  187. switch (mode) {
  188. case spv::ExecutionMode::VertexOrderCw:
  189. case spv::ExecutionMode::VertexOrderCcw:
  190. return true;
  191. default:
  192. return false;
  193. }
  194. })) {
  195. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  196. << "Tessellation execution model entry points can specify at "
  197. "most one of VertexOrderCw or VertexOrderCcw execution "
  198. "modes.";
  199. }
  200. break;
  201. case spv::ExecutionModel::Geometry:
  202. if (!execution_modes ||
  203. 1 != std::count_if(
  204. execution_modes->begin(), execution_modes->end(),
  205. [](const spv::ExecutionMode& mode) {
  206. switch (mode) {
  207. case spv::ExecutionMode::InputPoints:
  208. case spv::ExecutionMode::InputLines:
  209. case spv::ExecutionMode::InputLinesAdjacency:
  210. case spv::ExecutionMode::Triangles:
  211. case spv::ExecutionMode::InputTrianglesAdjacency:
  212. return true;
  213. default:
  214. return false;
  215. }
  216. })) {
  217. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  218. << "Geometry execution model entry points must specify "
  219. "exactly one of InputPoints, InputLines, "
  220. "InputLinesAdjacency, Triangles or InputTrianglesAdjacency "
  221. "execution modes.";
  222. }
  223. if (!execution_modes ||
  224. 1 != std::count_if(execution_modes->begin(), execution_modes->end(),
  225. [](const spv::ExecutionMode& mode) {
  226. switch (mode) {
  227. case spv::ExecutionMode::OutputPoints:
  228. case spv::ExecutionMode::OutputLineStrip:
  229. case spv::ExecutionMode::OutputTriangleStrip:
  230. return true;
  231. default:
  232. return false;
  233. }
  234. })) {
  235. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  236. << "Geometry execution model entry points must specify "
  237. "exactly one of OutputPoints, OutputLineStrip or "
  238. "OutputTriangleStrip execution modes.";
  239. }
  240. break;
  241. case spv::ExecutionModel::MeshEXT:
  242. if (!execution_modes ||
  243. 1 != std::count_if(execution_modes->begin(), execution_modes->end(),
  244. [](const spv::ExecutionMode& mode) {
  245. switch (mode) {
  246. case spv::ExecutionMode::OutputPoints:
  247. case spv::ExecutionMode::OutputLinesEXT:
  248. case spv::ExecutionMode::OutputTrianglesEXT:
  249. return true;
  250. default:
  251. return false;
  252. }
  253. })) {
  254. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  255. << "MeshEXT execution model entry points must specify exactly "
  256. "one of OutputPoints, OutputLinesEXT, or "
  257. "OutputTrianglesEXT Execution Modes.";
  258. } else if (2 != std::count_if(
  259. execution_modes->begin(), execution_modes->end(),
  260. [](const spv::ExecutionMode& mode) {
  261. switch (mode) {
  262. case spv::ExecutionMode::OutputPrimitivesEXT:
  263. case spv::ExecutionMode::OutputVertices:
  264. return true;
  265. default:
  266. return false;
  267. }
  268. })) {
  269. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  270. << "MeshEXT execution model entry points must specify both "
  271. "OutputPrimitivesEXT and OutputVertices Execution Modes.";
  272. }
  273. break;
  274. default:
  275. break;
  276. }
  277. }
  278. if (spvIsVulkanEnv(_.context()->target_env)) {
  279. switch (execution_model) {
  280. case spv::ExecutionModel::GLCompute:
  281. if (!execution_modes ||
  282. !execution_modes->count(spv::ExecutionMode::LocalSize)) {
  283. bool ok = false;
  284. for (auto& i : _.ordered_instructions()) {
  285. if (i.opcode() == spv::Op::OpDecorate) {
  286. if (i.operands().size() > 2) {
  287. if (i.GetOperandAs<spv::Decoration>(1) ==
  288. spv::Decoration::BuiltIn &&
  289. i.GetOperandAs<spv::BuiltIn>(2) ==
  290. spv::BuiltIn::WorkgroupSize) {
  291. ok = true;
  292. break;
  293. }
  294. }
  295. }
  296. if (i.opcode() == spv::Op::OpExecutionModeId) {
  297. const auto mode = i.GetOperandAs<spv::ExecutionMode>(1);
  298. if (mode == spv::ExecutionMode::LocalSizeId) {
  299. ok = true;
  300. break;
  301. }
  302. }
  303. }
  304. if (!ok) {
  305. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  306. << _.VkErrorID(6426)
  307. << "In the Vulkan environment, GLCompute execution model "
  308. "entry points require either the LocalSize or "
  309. "LocalSizeId execution mode or an object decorated with "
  310. "WorkgroupSize must be specified.";
  311. }
  312. }
  313. break;
  314. default:
  315. break;
  316. }
  317. }
  318. return SPV_SUCCESS;
  319. }
  320. spv_result_t ValidateExecutionMode(ValidationState_t& _,
  321. const Instruction* inst) {
  322. const auto entry_point_id = inst->GetOperandAs<uint32_t>(0);
  323. const auto found = std::find(_.entry_points().cbegin(),
  324. _.entry_points().cend(), entry_point_id);
  325. if (found == _.entry_points().cend()) {
  326. return _.diag(SPV_ERROR_INVALID_ID, inst)
  327. << "OpExecutionMode Entry Point <id> " << _.getIdName(entry_point_id)
  328. << " is not the Entry Point "
  329. "operand of an OpEntryPoint.";
  330. }
  331. const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
  332. if (inst->opcode() == spv::Op::OpExecutionModeId) {
  333. size_t operand_count = inst->operands().size();
  334. for (size_t i = 2; i < operand_count; ++i) {
  335. const auto operand_id = inst->GetOperandAs<uint32_t>(2);
  336. const auto* operand_inst = _.FindDef(operand_id);
  337. if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
  338. mode == spv::ExecutionMode::LocalSizeHintId ||
  339. mode == spv::ExecutionMode::LocalSizeId) {
  340. if (!spvOpcodeIsConstant(operand_inst->opcode())) {
  341. return _.diag(SPV_ERROR_INVALID_ID, inst)
  342. << "For OpExecutionModeId all Extra Operand ids must be "
  343. "constant "
  344. "instructions.";
  345. }
  346. } else {
  347. return _.diag(SPV_ERROR_INVALID_ID, inst)
  348. << "OpExecutionModeId is only valid when the Mode operand is an "
  349. "execution mode that takes Extra Operands that are id "
  350. "operands.";
  351. }
  352. }
  353. } else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
  354. mode == spv::ExecutionMode::LocalSizeHintId ||
  355. mode == spv::ExecutionMode::LocalSizeId) {
  356. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  357. << "OpExecutionMode is only valid when the Mode operand is an "
  358. "execution mode that takes no Extra Operands, or takes Extra "
  359. "Operands that are not id operands.";
  360. }
  361. const auto* models = _.GetExecutionModels(entry_point_id);
  362. switch (mode) {
  363. case spv::ExecutionMode::Invocations:
  364. case spv::ExecutionMode::InputPoints:
  365. case spv::ExecutionMode::InputLines:
  366. case spv::ExecutionMode::InputLinesAdjacency:
  367. case spv::ExecutionMode::InputTrianglesAdjacency:
  368. case spv::ExecutionMode::OutputLineStrip:
  369. case spv::ExecutionMode::OutputTriangleStrip:
  370. if (!std::all_of(models->begin(), models->end(),
  371. [](const spv::ExecutionModel& model) {
  372. return model == spv::ExecutionModel::Geometry;
  373. })) {
  374. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  375. << "Execution mode can only be used with the Geometry execution "
  376. "model.";
  377. }
  378. break;
  379. case spv::ExecutionMode::OutputPoints:
  380. if (!std::all_of(
  381. models->begin(), models->end(),
  382. [&_](const spv::ExecutionModel& model) {
  383. switch (model) {
  384. case spv::ExecutionModel::Geometry:
  385. return true;
  386. case spv::ExecutionModel::MeshNV:
  387. return _.HasCapability(spv::Capability::MeshShadingNV);
  388. case spv::ExecutionModel::MeshEXT:
  389. return _.HasCapability(spv::Capability::MeshShadingEXT);
  390. default:
  391. return false;
  392. }
  393. })) {
  394. if (_.HasCapability(spv::Capability::MeshShadingNV) ||
  395. _.HasCapability(spv::Capability::MeshShadingEXT)) {
  396. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  397. << "Execution mode can only be used with the Geometry "
  398. "MeshNV or MeshEXT execution model.";
  399. } else {
  400. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  401. << "Execution mode can only be used with the Geometry "
  402. "execution "
  403. "model.";
  404. }
  405. }
  406. break;
  407. case spv::ExecutionMode::SpacingEqual:
  408. case spv::ExecutionMode::SpacingFractionalEven:
  409. case spv::ExecutionMode::SpacingFractionalOdd:
  410. case spv::ExecutionMode::VertexOrderCw:
  411. case spv::ExecutionMode::VertexOrderCcw:
  412. case spv::ExecutionMode::PointMode:
  413. case spv::ExecutionMode::Quads:
  414. case spv::ExecutionMode::Isolines:
  415. if (!std::all_of(
  416. models->begin(), models->end(),
  417. [](const spv::ExecutionModel& model) {
  418. return (model == spv::ExecutionModel::TessellationControl) ||
  419. (model == spv::ExecutionModel::TessellationEvaluation);
  420. })) {
  421. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  422. << "Execution mode can only be used with a tessellation "
  423. "execution model.";
  424. }
  425. break;
  426. case spv::ExecutionMode::Triangles:
  427. if (!std::all_of(models->begin(), models->end(),
  428. [](const spv::ExecutionModel& model) {
  429. switch (model) {
  430. case spv::ExecutionModel::Geometry:
  431. case spv::ExecutionModel::TessellationControl:
  432. case spv::ExecutionModel::TessellationEvaluation:
  433. return true;
  434. default:
  435. return false;
  436. }
  437. })) {
  438. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  439. << "Execution mode can only be used with a Geometry or "
  440. "tessellation execution model.";
  441. }
  442. break;
  443. case spv::ExecutionMode::OutputVertices:
  444. if (!std::all_of(
  445. models->begin(), models->end(),
  446. [&_](const spv::ExecutionModel& model) {
  447. switch (model) {
  448. case spv::ExecutionModel::Geometry:
  449. case spv::ExecutionModel::TessellationControl:
  450. case spv::ExecutionModel::TessellationEvaluation:
  451. return true;
  452. case spv::ExecutionModel::MeshNV:
  453. return _.HasCapability(spv::Capability::MeshShadingNV);
  454. case spv::ExecutionModel::MeshEXT:
  455. return _.HasCapability(spv::Capability::MeshShadingEXT);
  456. default:
  457. return false;
  458. }
  459. })) {
  460. if (_.HasCapability(spv::Capability::MeshShadingNV) ||
  461. _.HasCapability(spv::Capability::MeshShadingEXT)) {
  462. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  463. << "Execution mode can only be used with a Geometry, "
  464. "tessellation, MeshNV or MeshEXT execution model.";
  465. } else {
  466. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  467. << "Execution mode can only be used with a Geometry or "
  468. "tessellation execution model.";
  469. }
  470. }
  471. break;
  472. case spv::ExecutionMode::OutputLinesEXT:
  473. case spv::ExecutionMode::OutputTrianglesEXT:
  474. case spv::ExecutionMode::OutputPrimitivesEXT:
  475. if (!std::all_of(models->begin(), models->end(),
  476. [](const spv::ExecutionModel& model) {
  477. return (model == spv::ExecutionModel::MeshEXT ||
  478. model == spv::ExecutionModel::MeshNV);
  479. })) {
  480. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  481. << "Execution mode can only be used with the MeshEXT or MeshNV "
  482. "execution "
  483. "model.";
  484. }
  485. break;
  486. case spv::ExecutionMode::PixelCenterInteger:
  487. case spv::ExecutionMode::OriginUpperLeft:
  488. case spv::ExecutionMode::OriginLowerLeft:
  489. case spv::ExecutionMode::EarlyFragmentTests:
  490. case spv::ExecutionMode::DepthReplacing:
  491. case spv::ExecutionMode::DepthGreater:
  492. case spv::ExecutionMode::DepthLess:
  493. case spv::ExecutionMode::DepthUnchanged:
  494. case spv::ExecutionMode::PixelInterlockOrderedEXT:
  495. case spv::ExecutionMode::PixelInterlockUnorderedEXT:
  496. case spv::ExecutionMode::SampleInterlockOrderedEXT:
  497. case spv::ExecutionMode::SampleInterlockUnorderedEXT:
  498. case spv::ExecutionMode::ShadingRateInterlockOrderedEXT:
  499. case spv::ExecutionMode::ShadingRateInterlockUnorderedEXT:
  500. case spv::ExecutionMode::EarlyAndLateFragmentTestsAMD:
  501. case spv::ExecutionMode::StencilRefUnchangedFrontAMD:
  502. case spv::ExecutionMode::StencilRefGreaterFrontAMD:
  503. case spv::ExecutionMode::StencilRefLessFrontAMD:
  504. case spv::ExecutionMode::StencilRefUnchangedBackAMD:
  505. case spv::ExecutionMode::StencilRefGreaterBackAMD:
  506. case spv::ExecutionMode::StencilRefLessBackAMD:
  507. if (!std::all_of(models->begin(), models->end(),
  508. [](const spv::ExecutionModel& model) {
  509. return model == spv::ExecutionModel::Fragment;
  510. })) {
  511. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  512. << "Execution mode can only be used with the Fragment execution "
  513. "model.";
  514. }
  515. break;
  516. case spv::ExecutionMode::LocalSizeHint:
  517. case spv::ExecutionMode::VecTypeHint:
  518. case spv::ExecutionMode::ContractionOff:
  519. case spv::ExecutionMode::LocalSizeHintId:
  520. if (!std::all_of(models->begin(), models->end(),
  521. [](const spv::ExecutionModel& model) {
  522. return model == spv::ExecutionModel::Kernel;
  523. })) {
  524. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  525. << "Execution mode can only be used with the Kernel execution "
  526. "model.";
  527. }
  528. break;
  529. case spv::ExecutionMode::LocalSize:
  530. case spv::ExecutionMode::LocalSizeId:
  531. if (mode == spv::ExecutionMode::LocalSizeId && !_.IsLocalSizeIdAllowed())
  532. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  533. << "LocalSizeId mode is not allowed by the current environment.";
  534. if (!std::all_of(
  535. models->begin(), models->end(),
  536. [&_](const spv::ExecutionModel& model) {
  537. switch (model) {
  538. case spv::ExecutionModel::Kernel:
  539. case spv::ExecutionModel::GLCompute:
  540. return true;
  541. case spv::ExecutionModel::TaskNV:
  542. case spv::ExecutionModel::MeshNV:
  543. return _.HasCapability(spv::Capability::MeshShadingNV);
  544. case spv::ExecutionModel::TaskEXT:
  545. case spv::ExecutionModel::MeshEXT:
  546. return _.HasCapability(spv::Capability::MeshShadingEXT);
  547. default:
  548. return false;
  549. }
  550. })) {
  551. if (_.HasCapability(spv::Capability::MeshShadingNV) ||
  552. _.HasCapability(spv::Capability::MeshShadingEXT)) {
  553. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  554. << "Execution mode can only be used with a Kernel, GLCompute, "
  555. "MeshNV, MeshEXT, TaskNV or TaskEXT execution model.";
  556. } else {
  557. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  558. << "Execution mode can only be used with a Kernel or "
  559. "GLCompute "
  560. "execution model.";
  561. }
  562. }
  563. default:
  564. break;
  565. }
  566. if (spvIsVulkanEnv(_.context()->target_env)) {
  567. if (mode == spv::ExecutionMode::OriginLowerLeft) {
  568. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  569. << _.VkErrorID(4653)
  570. << "In the Vulkan environment, the OriginLowerLeft execution mode "
  571. "must not be used.";
  572. }
  573. if (mode == spv::ExecutionMode::PixelCenterInteger) {
  574. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  575. << _.VkErrorID(4654)
  576. << "In the Vulkan environment, the PixelCenterInteger execution "
  577. "mode must not be used.";
  578. }
  579. }
  580. return SPV_SUCCESS;
  581. }
  582. spv_result_t ValidateMemoryModel(ValidationState_t& _,
  583. const Instruction* inst) {
  584. // Already produced an error if multiple memory model instructions are
  585. // present.
  586. if (_.memory_model() != spv::MemoryModel::VulkanKHR &&
  587. _.HasCapability(spv::Capability::VulkanMemoryModelKHR)) {
  588. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  589. << "VulkanMemoryModelKHR capability must only be specified if "
  590. "the VulkanKHR memory model is used.";
  591. }
  592. if (spvIsOpenCLEnv(_.context()->target_env)) {
  593. if ((_.addressing_model() != spv::AddressingModel::Physical32) &&
  594. (_.addressing_model() != spv::AddressingModel::Physical64)) {
  595. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  596. << "Addressing model must be Physical32 or Physical64 "
  597. << "in the OpenCL environment.";
  598. }
  599. if (_.memory_model() != spv::MemoryModel::OpenCL) {
  600. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  601. << "Memory model must be OpenCL in the OpenCL environment.";
  602. }
  603. }
  604. if (spvIsVulkanEnv(_.context()->target_env)) {
  605. if ((_.addressing_model() != spv::AddressingModel::Logical) &&
  606. (_.addressing_model() !=
  607. spv::AddressingModel::PhysicalStorageBuffer64)) {
  608. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  609. << _.VkErrorID(4635)
  610. << "Addressing model must be Logical or PhysicalStorageBuffer64 "
  611. << "in the Vulkan environment.";
  612. }
  613. }
  614. return SPV_SUCCESS;
  615. }
  616. } // namespace
  617. spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
  618. switch (inst->opcode()) {
  619. case spv::Op::OpEntryPoint:
  620. if (auto error = ValidateEntryPoint(_, inst)) return error;
  621. break;
  622. case spv::Op::OpExecutionMode:
  623. case spv::Op::OpExecutionModeId:
  624. if (auto error = ValidateExecutionMode(_, inst)) return error;
  625. break;
  626. case spv::Op::OpMemoryModel:
  627. if (auto error = ValidateMemoryModel(_, inst)) return error;
  628. break;
  629. default:
  630. break;
  631. }
  632. return SPV_SUCCESS;
  633. }
  634. } // namespace val
  635. } // namespace spvtools