validate_capability.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. // Copyright (c) 2017 Google Inc.
  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. // Validates OpCapability instruction.
  15. #include <cassert>
  16. #include <string>
  17. #include "source/opcode.h"
  18. #include "source/table2.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. bool IsSupportGuaranteedVulkan_1_0(uint32_t capability) {
  26. switch (spv::Capability(capability)) {
  27. case spv::Capability::Matrix:
  28. case spv::Capability::Shader:
  29. case spv::Capability::InputAttachment:
  30. case spv::Capability::Sampled1D:
  31. case spv::Capability::Image1D:
  32. case spv::Capability::SampledBuffer:
  33. case spv::Capability::ImageBuffer:
  34. case spv::Capability::ImageQuery:
  35. case spv::Capability::DerivativeControl:
  36. return true;
  37. default:
  38. break;
  39. }
  40. return false;
  41. }
  42. bool IsSupportGuaranteedVulkan_1_1(uint32_t capability) {
  43. if (IsSupportGuaranteedVulkan_1_0(capability)) return true;
  44. switch (spv::Capability(capability)) {
  45. case spv::Capability::DeviceGroup:
  46. case spv::Capability::MultiView:
  47. return true;
  48. default:
  49. break;
  50. }
  51. return false;
  52. }
  53. bool IsSupportGuaranteedVulkan_1_2(uint32_t capability) {
  54. if (IsSupportGuaranteedVulkan_1_1(capability)) return true;
  55. switch (spv::Capability(capability)) {
  56. case spv::Capability::ShaderNonUniform:
  57. return true;
  58. default:
  59. break;
  60. }
  61. return false;
  62. }
  63. bool IsSupportGuaranteedVulkan_1_3(uint32_t capability) {
  64. if (IsSupportGuaranteedVulkan_1_2(capability)) return true;
  65. switch (spv::Capability(capability)) {
  66. case spv::Capability::DotProduct:
  67. case spv::Capability::DotProductInputAll:
  68. case spv::Capability::DotProductInput4x8Bit:
  69. case spv::Capability::DotProductInput4x8BitPacked:
  70. case spv::Capability::VulkanMemoryModel:
  71. case spv::Capability::VulkanMemoryModelDeviceScope:
  72. case spv::Capability::PhysicalStorageBufferAddresses:
  73. case spv::Capability::DemoteToHelperInvocation:
  74. return true;
  75. default:
  76. break;
  77. }
  78. return false;
  79. }
  80. bool IsSupportGuaranteedVulkan_1_4(uint32_t capability) {
  81. if (IsSupportGuaranteedVulkan_1_3(capability)) return true;
  82. switch (spv::Capability(capability)) {
  83. case spv::Capability::UniformBufferArrayDynamicIndexing:
  84. case spv::Capability::SampledImageArrayDynamicIndexing:
  85. case spv::Capability::StorageBufferArrayDynamicIndexing:
  86. case spv::Capability::StorageImageArrayDynamicIndexing:
  87. case spv::Capability::Int16:
  88. case spv::Capability::StorageBuffer16BitAccess:
  89. case spv::Capability::VariablePointers:
  90. case spv::Capability::VariablePointersStorageBuffer:
  91. case spv::Capability::UniformTexelBufferArrayDynamicIndexing:
  92. case spv::Capability::StorageTexelBufferArrayDynamicIndexing:
  93. case spv::Capability::Int8:
  94. case spv::Capability::StorageBuffer8BitAccess:
  95. case spv::Capability::FloatControls2:
  96. case spv::Capability::SampleRateShading:
  97. case spv::Capability::StorageImageExtendedFormats:
  98. case spv::Capability::ImageGatherExtended:
  99. return true;
  100. default:
  101. break;
  102. }
  103. return false;
  104. }
  105. bool IsSupportOptionalVulkan_1_0(uint32_t capability) {
  106. switch (spv::Capability(capability)) {
  107. case spv::Capability::Geometry:
  108. case spv::Capability::Tessellation:
  109. case spv::Capability::Float64:
  110. case spv::Capability::Int64:
  111. case spv::Capability::Int16:
  112. case spv::Capability::TessellationPointSize:
  113. case spv::Capability::GeometryPointSize:
  114. case spv::Capability::ImageGatherExtended:
  115. case spv::Capability::StorageImageMultisample:
  116. case spv::Capability::UniformBufferArrayDynamicIndexing:
  117. case spv::Capability::SampledImageArrayDynamicIndexing:
  118. case spv::Capability::StorageBufferArrayDynamicIndexing:
  119. case spv::Capability::StorageImageArrayDynamicIndexing:
  120. case spv::Capability::ClipDistance:
  121. case spv::Capability::CullDistance:
  122. case spv::Capability::ImageCubeArray:
  123. case spv::Capability::SampleRateShading:
  124. case spv::Capability::SparseResidency:
  125. case spv::Capability::MinLod:
  126. case spv::Capability::SampledCubeArray:
  127. case spv::Capability::ImageMSArray:
  128. case spv::Capability::StorageImageExtendedFormats:
  129. case spv::Capability::InterpolationFunction:
  130. case spv::Capability::StorageImageReadWithoutFormat:
  131. case spv::Capability::StorageImageWriteWithoutFormat:
  132. case spv::Capability::MultiViewport:
  133. case spv::Capability::Int64Atomics:
  134. case spv::Capability::TransformFeedback:
  135. case spv::Capability::GeometryStreams:
  136. case spv::Capability::Float16:
  137. case spv::Capability::Int8:
  138. case spv::Capability::BFloat16TypeKHR:
  139. case spv::Capability::Float8EXT:
  140. return true;
  141. default:
  142. break;
  143. }
  144. return false;
  145. }
  146. bool IsSupportOptionalVulkan_1_1(uint32_t capability) {
  147. if (IsSupportOptionalVulkan_1_0(capability)) return true;
  148. switch (spv::Capability(capability)) {
  149. case spv::Capability::GroupNonUniform:
  150. case spv::Capability::GroupNonUniformVote:
  151. case spv::Capability::GroupNonUniformArithmetic:
  152. case spv::Capability::GroupNonUniformBallot:
  153. case spv::Capability::GroupNonUniformShuffle:
  154. case spv::Capability::GroupNonUniformShuffleRelative:
  155. case spv::Capability::GroupNonUniformClustered:
  156. case spv::Capability::GroupNonUniformQuad:
  157. case spv::Capability::DrawParameters:
  158. // Alias spv::Capability::StorageBuffer16BitAccess.
  159. case spv::Capability::StorageUniformBufferBlock16:
  160. // Alias spv::Capability::UniformAndStorageBuffer16BitAccess.
  161. case spv::Capability::StorageUniform16:
  162. case spv::Capability::StoragePushConstant16:
  163. case spv::Capability::StorageInputOutput16:
  164. case spv::Capability::DeviceGroup:
  165. case spv::Capability::MultiView:
  166. case spv::Capability::VariablePointersStorageBuffer:
  167. case spv::Capability::VariablePointers:
  168. return true;
  169. default:
  170. break;
  171. }
  172. return false;
  173. }
  174. bool IsSupportOptionalVulkan_1_2(uint32_t capability) {
  175. if (IsSupportOptionalVulkan_1_1(capability)) return true;
  176. switch (spv::Capability(capability)) {
  177. case spv::Capability::DenormPreserve:
  178. case spv::Capability::DenormFlushToZero:
  179. case spv::Capability::SignedZeroInfNanPreserve:
  180. case spv::Capability::RoundingModeRTE:
  181. case spv::Capability::RoundingModeRTZ:
  182. case spv::Capability::VulkanMemoryModel:
  183. case spv::Capability::VulkanMemoryModelDeviceScope:
  184. case spv::Capability::StorageBuffer8BitAccess:
  185. case spv::Capability::UniformAndStorageBuffer8BitAccess:
  186. case spv::Capability::StoragePushConstant8:
  187. case spv::Capability::ShaderViewportIndex:
  188. case spv::Capability::ShaderLayer:
  189. case spv::Capability::PhysicalStorageBufferAddresses:
  190. case spv::Capability::RuntimeDescriptorArray:
  191. case spv::Capability::UniformTexelBufferArrayDynamicIndexing:
  192. case spv::Capability::StorageTexelBufferArrayDynamicIndexing:
  193. case spv::Capability::UniformBufferArrayNonUniformIndexing:
  194. case spv::Capability::SampledImageArrayNonUniformIndexing:
  195. case spv::Capability::StorageBufferArrayNonUniformIndexing:
  196. case spv::Capability::StorageImageArrayNonUniformIndexing:
  197. case spv::Capability::InputAttachmentArrayNonUniformIndexing:
  198. case spv::Capability::UniformTexelBufferArrayNonUniformIndexing:
  199. case spv::Capability::StorageTexelBufferArrayNonUniformIndexing:
  200. return true;
  201. default:
  202. break;
  203. }
  204. return false;
  205. }
  206. // Vulkan 1.3 only added required features.
  207. bool IsSupportOptionalVulkan_1_3(uint32_t capability) {
  208. return IsSupportOptionalVulkan_1_2(capability);
  209. }
  210. // Vulkan 1.4 only added required features.
  211. bool IsSupportOptionalVulkan_1_4(uint32_t capability) {
  212. return IsSupportOptionalVulkan_1_3(capability);
  213. }
  214. bool IsSupportGuaranteedOpenCL_1_2(uint32_t capability, bool embedded_profile) {
  215. switch (spv::Capability(capability)) {
  216. case spv::Capability::Addresses:
  217. case spv::Capability::Float16Buffer:
  218. case spv::Capability::Int16:
  219. case spv::Capability::Int8:
  220. case spv::Capability::Kernel:
  221. case spv::Capability::Linkage:
  222. case spv::Capability::Vector16:
  223. return true;
  224. case spv::Capability::Int64:
  225. return !embedded_profile;
  226. default:
  227. break;
  228. }
  229. return false;
  230. }
  231. bool IsSupportGuaranteedOpenCL_2_0(uint32_t capability, bool embedded_profile) {
  232. if (IsSupportGuaranteedOpenCL_1_2(capability, embedded_profile)) return true;
  233. switch (spv::Capability(capability)) {
  234. case spv::Capability::DeviceEnqueue:
  235. case spv::Capability::GenericPointer:
  236. case spv::Capability::Groups:
  237. case spv::Capability::Pipes:
  238. return true;
  239. default:
  240. break;
  241. }
  242. return false;
  243. }
  244. bool IsSupportGuaranteedOpenCL_2_2(uint32_t capability, bool embedded_profile) {
  245. if (IsSupportGuaranteedOpenCL_2_0(capability, embedded_profile)) return true;
  246. switch (spv::Capability(capability)) {
  247. case spv::Capability::SubgroupDispatch:
  248. case spv::Capability::PipeStorage:
  249. return true;
  250. default:
  251. break;
  252. }
  253. return false;
  254. }
  255. bool IsSupportOptionalOpenCL_1_2(uint32_t capability) {
  256. switch (spv::Capability(capability)) {
  257. case spv::Capability::ImageBasic:
  258. case spv::Capability::Float64:
  259. case spv::Capability::Float16:
  260. return true;
  261. default:
  262. break;
  263. }
  264. return false;
  265. }
  266. // Checks if |capability| was enabled by extension.
  267. bool IsEnabledByExtension(ValidationState_t& _, uint32_t capability) {
  268. const spvtools::OperandDesc* operand_desc = nullptr;
  269. spvtools::LookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  270. &operand_desc);
  271. // operand_desc is expected to be not null, otherwise validator would have
  272. // failed at an earlier stage. This 'assert' is 'just in case'.
  273. assert(operand_desc);
  274. ExtensionSet operand_exts(operand_desc->extensions_range.count(),
  275. operand_desc->extensions().data());
  276. if (operand_exts.empty()) return false;
  277. return _.HasAnyOfExtensions(operand_exts);
  278. }
  279. bool IsEnabledByCapabilityOpenCL_1_2(ValidationState_t& _,
  280. uint32_t capability) {
  281. if (_.HasCapability(spv::Capability::ImageBasic)) {
  282. switch (spv::Capability(capability)) {
  283. case spv::Capability::LiteralSampler:
  284. case spv::Capability::Sampled1D:
  285. case spv::Capability::Image1D:
  286. case spv::Capability::SampledBuffer:
  287. case spv::Capability::ImageBuffer:
  288. return true;
  289. default:
  290. break;
  291. }
  292. return false;
  293. }
  294. return false;
  295. }
  296. bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _,
  297. uint32_t capability) {
  298. if (_.HasCapability(spv::Capability::ImageBasic)) {
  299. switch (spv::Capability(capability)) {
  300. case spv::Capability::ImageReadWrite:
  301. case spv::Capability::LiteralSampler:
  302. case spv::Capability::Sampled1D:
  303. case spv::Capability::Image1D:
  304. case spv::Capability::SampledBuffer:
  305. case spv::Capability::ImageBuffer:
  306. return true;
  307. default:
  308. break;
  309. }
  310. return false;
  311. }
  312. return false;
  313. }
  314. } // namespace
  315. // Validates that capability declarations use operands allowed in the current
  316. // context.
  317. spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) {
  318. if (inst->opcode() != spv::Op::OpCapability &&
  319. inst->opcode() != spv::Op::OpConditionalCapabilityINTEL)
  320. return SPV_SUCCESS;
  321. assert(!((inst->opcode() == spv::Op::OpCapability) ^
  322. (inst->operands().size() == 1)));
  323. assert(!((inst->opcode() == spv::Op::OpConditionalCapabilityINTEL) ^
  324. (inst->operands().size() == 2)));
  325. const uint32_t i_cap =
  326. inst->opcode() == spv::Op::OpConditionalCapabilityINTEL ? 1 : 0;
  327. const spv_parsed_operand_t& operand = inst->operand(i_cap);
  328. assert(operand.num_words == 1);
  329. assert(operand.offset < inst->words().size());
  330. const uint32_t capability = inst->word(operand.offset);
  331. const auto capability_str = [capability]() {
  332. const spvtools::OperandDesc* desc = nullptr;
  333. if (spvtools::LookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  334. &desc) != SPV_SUCCESS ||
  335. !desc) {
  336. return std::string("Unknown");
  337. }
  338. return std::string(desc->name().data());
  339. };
  340. const auto env = _.context()->target_env;
  341. const bool opencl_embedded = env == SPV_ENV_OPENCL_EMBEDDED_1_2 ||
  342. env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  343. env == SPV_ENV_OPENCL_EMBEDDED_2_1 ||
  344. env == SPV_ENV_OPENCL_EMBEDDED_2_2;
  345. const std::string opencl_profile = opencl_embedded ? "Embedded" : "Full";
  346. if (env == SPV_ENV_VULKAN_1_0) {
  347. if (!IsSupportGuaranteedVulkan_1_0(capability) &&
  348. !IsSupportOptionalVulkan_1_0(capability) &&
  349. !IsEnabledByExtension(_, capability)) {
  350. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  351. << "Capability " << capability_str()
  352. << " is not allowed by Vulkan 1.0 specification"
  353. << " (or requires extension)";
  354. }
  355. } else if (env == SPV_ENV_VULKAN_1_1) {
  356. if (!IsSupportGuaranteedVulkan_1_1(capability) &&
  357. !IsSupportOptionalVulkan_1_1(capability) &&
  358. !IsEnabledByExtension(_, capability)) {
  359. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  360. << "Capability " << capability_str()
  361. << " is not allowed by Vulkan 1.1 specification"
  362. << " (or requires extension)";
  363. }
  364. } else if (env == SPV_ENV_VULKAN_1_2) {
  365. if (!IsSupportGuaranteedVulkan_1_2(capability) &&
  366. !IsSupportOptionalVulkan_1_2(capability) &&
  367. !IsEnabledByExtension(_, capability)) {
  368. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  369. << "Capability " << capability_str()
  370. << " is not allowed by Vulkan 1.2 specification"
  371. << " (or requires extension)";
  372. }
  373. } else if (env == SPV_ENV_VULKAN_1_3) {
  374. if (!IsSupportGuaranteedVulkan_1_3(capability) &&
  375. !IsSupportOptionalVulkan_1_3(capability) &&
  376. !IsEnabledByExtension(_, capability)) {
  377. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  378. << "Capability " << capability_str()
  379. << " is not allowed by Vulkan 1.3 specification"
  380. << " (or requires extension)";
  381. }
  382. } else if (env == SPV_ENV_VULKAN_1_4) {
  383. if (!IsSupportGuaranteedVulkan_1_4(capability) &&
  384. !IsSupportOptionalVulkan_1_4(capability) &&
  385. !IsEnabledByExtension(_, capability)) {
  386. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  387. << "Capability " << capability_str()
  388. << " is not allowed by Vulkan 1.4 specification"
  389. << " (or requires extension)";
  390. }
  391. } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) {
  392. if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) &&
  393. !IsSupportOptionalOpenCL_1_2(capability) &&
  394. !IsEnabledByExtension(_, capability) &&
  395. !IsEnabledByCapabilityOpenCL_1_2(_, capability)) {
  396. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  397. << "Capability " << capability_str()
  398. << " is not allowed by OpenCL 1.2 " << opencl_profile
  399. << " Profile specification"
  400. << " (or requires extension or capability)";
  401. }
  402. } else if (env == SPV_ENV_OPENCL_2_0 || env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  403. env == SPV_ENV_OPENCL_2_1 || env == SPV_ENV_OPENCL_EMBEDDED_2_1) {
  404. if (!IsSupportGuaranteedOpenCL_2_0(capability, opencl_embedded) &&
  405. !IsSupportOptionalOpenCL_1_2(capability) &&
  406. !IsEnabledByExtension(_, capability) &&
  407. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  408. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  409. << "Capability " << capability_str()
  410. << " is not allowed by OpenCL 2.0/2.1 " << opencl_profile
  411. << " Profile specification"
  412. << " (or requires extension or capability)";
  413. }
  414. } else if (env == SPV_ENV_OPENCL_2_2 || env == SPV_ENV_OPENCL_EMBEDDED_2_2) {
  415. if (!IsSupportGuaranteedOpenCL_2_2(capability, opencl_embedded) &&
  416. !IsSupportOptionalOpenCL_1_2(capability) &&
  417. !IsEnabledByExtension(_, capability) &&
  418. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  419. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  420. << "Capability " << capability_str()
  421. << " is not allowed by OpenCL 2.2 " << opencl_profile
  422. << " Profile specification"
  423. << " (or requires extension or capability)";
  424. }
  425. }
  426. return SPV_SUCCESS;
  427. }
  428. } // namespace val
  429. } // namespace spvtools