validate_capability.cpp 14 KB

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