validate_capability.cpp 13 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 "source/val/validate.h"
  16. #include <cassert>
  17. #include <string>
  18. #include <unordered_set>
  19. #include "source/diagnostic.h"
  20. #include "source/opcode.h"
  21. #include "source/val/instruction.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 (capability) {
  28. case SpvCapabilityMatrix:
  29. case SpvCapabilityShader:
  30. case SpvCapabilityInputAttachment:
  31. case SpvCapabilitySampled1D:
  32. case SpvCapabilityImage1D:
  33. case SpvCapabilitySampledBuffer:
  34. case SpvCapabilityImageBuffer:
  35. case SpvCapabilityImageQuery:
  36. case SpvCapabilityDerivativeControl:
  37. return true;
  38. }
  39. return false;
  40. }
  41. bool IsSupportGuaranteedVulkan_1_1(uint32_t capability) {
  42. if (IsSupportGuaranteedVulkan_1_0(capability)) return true;
  43. switch (capability) {
  44. case SpvCapabilityDeviceGroup:
  45. case SpvCapabilityMultiView:
  46. return true;
  47. }
  48. return false;
  49. }
  50. bool IsSupportGuaranteedVulkan_1_2(uint32_t capability) {
  51. if (IsSupportGuaranteedVulkan_1_1(capability)) return true;
  52. switch (capability) {
  53. case SpvCapabilityShaderNonUniform:
  54. return true;
  55. }
  56. return false;
  57. }
  58. bool IsSupportOptionalVulkan_1_0(uint32_t capability) {
  59. switch (capability) {
  60. case SpvCapabilityGeometry:
  61. case SpvCapabilityTessellation:
  62. case SpvCapabilityFloat64:
  63. case SpvCapabilityInt64:
  64. case SpvCapabilityInt16:
  65. case SpvCapabilityTessellationPointSize:
  66. case SpvCapabilityGeometryPointSize:
  67. case SpvCapabilityImageGatherExtended:
  68. case SpvCapabilityStorageImageMultisample:
  69. case SpvCapabilityUniformBufferArrayDynamicIndexing:
  70. case SpvCapabilitySampledImageArrayDynamicIndexing:
  71. case SpvCapabilityStorageBufferArrayDynamicIndexing:
  72. case SpvCapabilityStorageImageArrayDynamicIndexing:
  73. case SpvCapabilityClipDistance:
  74. case SpvCapabilityCullDistance:
  75. case SpvCapabilityImageCubeArray:
  76. case SpvCapabilitySampleRateShading:
  77. case SpvCapabilitySparseResidency:
  78. case SpvCapabilityMinLod:
  79. case SpvCapabilitySampledCubeArray:
  80. case SpvCapabilityImageMSArray:
  81. case SpvCapabilityStorageImageExtendedFormats:
  82. case SpvCapabilityInterpolationFunction:
  83. case SpvCapabilityStorageImageReadWithoutFormat:
  84. case SpvCapabilityStorageImageWriteWithoutFormat:
  85. case SpvCapabilityMultiViewport:
  86. case SpvCapabilityInt64Atomics:
  87. case SpvCapabilityTransformFeedback:
  88. case SpvCapabilityGeometryStreams:
  89. case SpvCapabilityFloat16:
  90. case SpvCapabilityInt8:
  91. return true;
  92. }
  93. return false;
  94. }
  95. bool IsSupportOptionalVulkan_1_1(uint32_t capability) {
  96. if (IsSupportOptionalVulkan_1_0(capability)) return true;
  97. switch (capability) {
  98. case SpvCapabilityGroupNonUniform:
  99. case SpvCapabilityGroupNonUniformVote:
  100. case SpvCapabilityGroupNonUniformArithmetic:
  101. case SpvCapabilityGroupNonUniformBallot:
  102. case SpvCapabilityGroupNonUniformShuffle:
  103. case SpvCapabilityGroupNonUniformShuffleRelative:
  104. case SpvCapabilityGroupNonUniformClustered:
  105. case SpvCapabilityGroupNonUniformQuad:
  106. case SpvCapabilityDrawParameters:
  107. // Alias SpvCapabilityStorageBuffer16BitAccess.
  108. case SpvCapabilityStorageUniformBufferBlock16:
  109. // Alias SpvCapabilityUniformAndStorageBuffer16BitAccess.
  110. case SpvCapabilityStorageUniform16:
  111. case SpvCapabilityStoragePushConstant16:
  112. case SpvCapabilityStorageInputOutput16:
  113. case SpvCapabilityDeviceGroup:
  114. case SpvCapabilityMultiView:
  115. case SpvCapabilityVariablePointersStorageBuffer:
  116. case SpvCapabilityVariablePointers:
  117. return true;
  118. }
  119. return false;
  120. }
  121. bool IsSupportOptionalVulkan_1_2(uint32_t capability) {
  122. if (IsSupportOptionalVulkan_1_1(capability)) return true;
  123. switch (capability) {
  124. case SpvCapabilityDenormPreserve:
  125. case SpvCapabilityDenormFlushToZero:
  126. case SpvCapabilitySignedZeroInfNanPreserve:
  127. case SpvCapabilityRoundingModeRTE:
  128. case SpvCapabilityRoundingModeRTZ:
  129. case SpvCapabilityVulkanMemoryModel:
  130. case SpvCapabilityVulkanMemoryModelDeviceScope:
  131. case SpvCapabilityStorageBuffer8BitAccess:
  132. case SpvCapabilityUniformAndStorageBuffer8BitAccess:
  133. case SpvCapabilityStoragePushConstant8:
  134. case SpvCapabilityShaderViewportIndex:
  135. case SpvCapabilityShaderLayer:
  136. case SpvCapabilityPhysicalStorageBufferAddresses:
  137. case SpvCapabilityRuntimeDescriptorArray:
  138. case SpvCapabilityUniformTexelBufferArrayDynamicIndexing:
  139. case SpvCapabilityStorageTexelBufferArrayDynamicIndexing:
  140. case SpvCapabilityUniformBufferArrayNonUniformIndexing:
  141. case SpvCapabilitySampledImageArrayNonUniformIndexing:
  142. case SpvCapabilityStorageBufferArrayNonUniformIndexing:
  143. case SpvCapabilityStorageImageArrayNonUniformIndexing:
  144. case SpvCapabilityInputAttachmentArrayNonUniformIndexing:
  145. case SpvCapabilityUniformTexelBufferArrayNonUniformIndexing:
  146. case SpvCapabilityStorageTexelBufferArrayNonUniformIndexing:
  147. return true;
  148. }
  149. return false;
  150. }
  151. bool IsSupportGuaranteedOpenCL_1_2(uint32_t capability, bool embedded_profile) {
  152. switch (capability) {
  153. case SpvCapabilityAddresses:
  154. case SpvCapabilityFloat16Buffer:
  155. case SpvCapabilityGroups:
  156. case SpvCapabilityInt16:
  157. case SpvCapabilityInt8:
  158. case SpvCapabilityKernel:
  159. case SpvCapabilityLinkage:
  160. case SpvCapabilityVector16:
  161. return true;
  162. case SpvCapabilityInt64:
  163. return !embedded_profile;
  164. case SpvCapabilityPipes:
  165. return embedded_profile;
  166. }
  167. return false;
  168. }
  169. bool IsSupportGuaranteedOpenCL_2_0(uint32_t capability, bool embedded_profile) {
  170. if (IsSupportGuaranteedOpenCL_1_2(capability, embedded_profile)) return true;
  171. switch (capability) {
  172. case SpvCapabilityDeviceEnqueue:
  173. case SpvCapabilityGenericPointer:
  174. case SpvCapabilityPipes:
  175. return true;
  176. }
  177. return false;
  178. }
  179. bool IsSupportGuaranteedOpenCL_2_2(uint32_t capability, bool embedded_profile) {
  180. if (IsSupportGuaranteedOpenCL_2_0(capability, embedded_profile)) return true;
  181. switch (capability) {
  182. case SpvCapabilitySubgroupDispatch:
  183. case SpvCapabilityPipeStorage:
  184. return true;
  185. }
  186. return false;
  187. }
  188. bool IsSupportOptionalOpenCL_1_2(uint32_t capability) {
  189. switch (capability) {
  190. case SpvCapabilityImageBasic:
  191. case SpvCapabilityFloat64:
  192. return true;
  193. }
  194. return false;
  195. }
  196. // Checks if |capability| was enabled by extension.
  197. bool IsEnabledByExtension(ValidationState_t& _, uint32_t capability) {
  198. spv_operand_desc operand_desc = nullptr;
  199. _.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  200. &operand_desc);
  201. // operand_desc is expected to be not null, otherwise validator would have
  202. // failed at an earlier stage. This 'assert' is 'just in case'.
  203. assert(operand_desc);
  204. ExtensionSet operand_exts(operand_desc->numExtensions,
  205. operand_desc->extensions);
  206. if (operand_exts.IsEmpty()) return false;
  207. return _.HasAnyOfExtensions(operand_exts);
  208. }
  209. bool IsEnabledByCapabilityOpenCL_1_2(ValidationState_t& _,
  210. uint32_t capability) {
  211. if (_.HasCapability(SpvCapabilityImageBasic)) {
  212. switch (capability) {
  213. case SpvCapabilityLiteralSampler:
  214. case SpvCapabilitySampled1D:
  215. case SpvCapabilityImage1D:
  216. case SpvCapabilitySampledBuffer:
  217. case SpvCapabilityImageBuffer:
  218. return true;
  219. }
  220. return false;
  221. }
  222. return false;
  223. }
  224. bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _,
  225. uint32_t capability) {
  226. if (_.HasCapability(SpvCapabilityImageBasic)) {
  227. switch (capability) {
  228. case SpvCapabilityImageReadWrite:
  229. case SpvCapabilityLiteralSampler:
  230. case SpvCapabilitySampled1D:
  231. case SpvCapabilityImage1D:
  232. case SpvCapabilitySampledBuffer:
  233. case SpvCapabilityImageBuffer:
  234. return true;
  235. }
  236. return false;
  237. }
  238. return false;
  239. }
  240. bool IsSupportGuaranteedWebGPU(uint32_t capability) {
  241. switch (capability) {
  242. case SpvCapabilityMatrix:
  243. case SpvCapabilityShader:
  244. case SpvCapabilitySampled1D:
  245. case SpvCapabilityImage1D:
  246. case SpvCapabilityDerivativeControl:
  247. case SpvCapabilityImageQuery:
  248. return true;
  249. }
  250. return false;
  251. }
  252. } // namespace
  253. // Validates that capability declarations use operands allowed in the current
  254. // context.
  255. spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) {
  256. if (inst->opcode() != SpvOpCapability) return SPV_SUCCESS;
  257. assert(inst->operands().size() == 1);
  258. const spv_parsed_operand_t& operand = inst->operand(0);
  259. assert(operand.num_words == 1);
  260. assert(operand.offset < inst->words().size());
  261. const uint32_t capability = inst->word(operand.offset);
  262. const auto capability_str = [&_, capability]() {
  263. spv_operand_desc desc = nullptr;
  264. if (_.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  265. &desc) != SPV_SUCCESS ||
  266. !desc) {
  267. return std::string("Unknown");
  268. }
  269. return std::string(desc->name);
  270. };
  271. const auto env = _.context()->target_env;
  272. const bool opencl_embedded = env == SPV_ENV_OPENCL_EMBEDDED_1_2 ||
  273. env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  274. env == SPV_ENV_OPENCL_EMBEDDED_2_1 ||
  275. env == SPV_ENV_OPENCL_EMBEDDED_2_2;
  276. const std::string opencl_profile = opencl_embedded ? "Embedded" : "Full";
  277. if (env == SPV_ENV_VULKAN_1_0) {
  278. if (!IsSupportGuaranteedVulkan_1_0(capability) &&
  279. !IsSupportOptionalVulkan_1_0(capability) &&
  280. !IsEnabledByExtension(_, capability)) {
  281. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  282. << "Capability " << capability_str()
  283. << " is not allowed by Vulkan 1.0 specification"
  284. << " (or requires extension)";
  285. }
  286. } else if (env == SPV_ENV_VULKAN_1_1) {
  287. if (!IsSupportGuaranteedVulkan_1_1(capability) &&
  288. !IsSupportOptionalVulkan_1_1(capability) &&
  289. !IsEnabledByExtension(_, capability)) {
  290. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  291. << "Capability " << capability_str()
  292. << " is not allowed by Vulkan 1.1 specification"
  293. << " (or requires extension)";
  294. }
  295. } else if (env == SPV_ENV_VULKAN_1_2) {
  296. if (!IsSupportGuaranteedVulkan_1_2(capability) &&
  297. !IsSupportOptionalVulkan_1_2(capability) &&
  298. !IsEnabledByExtension(_, capability)) {
  299. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  300. << "Capability " << capability_str()
  301. << " is not allowed by Vulkan 1.2 specification"
  302. << " (or requires extension)";
  303. }
  304. } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) {
  305. if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) &&
  306. !IsSupportOptionalOpenCL_1_2(capability) &&
  307. !IsEnabledByExtension(_, capability) &&
  308. !IsEnabledByCapabilityOpenCL_1_2(_, capability)) {
  309. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  310. << "Capability " << capability_str()
  311. << " is not allowed by OpenCL 1.2 " << opencl_profile
  312. << " Profile specification"
  313. << " (or requires extension or capability)";
  314. }
  315. } else if (env == SPV_ENV_OPENCL_2_0 || env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  316. env == SPV_ENV_OPENCL_2_1 || env == SPV_ENV_OPENCL_EMBEDDED_2_1) {
  317. if (!IsSupportGuaranteedOpenCL_2_0(capability, opencl_embedded) &&
  318. !IsSupportOptionalOpenCL_1_2(capability) &&
  319. !IsEnabledByExtension(_, capability) &&
  320. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  321. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  322. << "Capability " << capability_str()
  323. << " is not allowed by OpenCL 2.0/2.1 " << opencl_profile
  324. << " Profile specification"
  325. << " (or requires extension or capability)";
  326. }
  327. } else if (env == SPV_ENV_OPENCL_2_2 || env == SPV_ENV_OPENCL_EMBEDDED_2_2) {
  328. if (!IsSupportGuaranteedOpenCL_2_2(capability, opencl_embedded) &&
  329. !IsSupportOptionalOpenCL_1_2(capability) &&
  330. !IsEnabledByExtension(_, capability) &&
  331. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  332. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  333. << "Capability " << capability_str()
  334. << " is not allowed by OpenCL 2.2 " << opencl_profile
  335. << " Profile specification"
  336. << " (or requires extension or capability)";
  337. }
  338. } else if (env == SPV_ENV_WEBGPU_0) {
  339. if (!IsSupportGuaranteedWebGPU(capability) &&
  340. !IsEnabledByExtension(_, capability)) {
  341. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  342. << "Capability " << capability_str()
  343. << " is not allowed by WebGPU specification"
  344. << " (or requires extension)";
  345. }
  346. }
  347. return SPV_SUCCESS;
  348. }
  349. } // namespace val
  350. } // namespace spvtools