validate_capability.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 (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 SpvCapabilityInt16:
  156. case SpvCapabilityInt8:
  157. case SpvCapabilityKernel:
  158. case SpvCapabilityLinkage:
  159. case SpvCapabilityVector16:
  160. return true;
  161. case SpvCapabilityInt64:
  162. return !embedded_profile;
  163. }
  164. return false;
  165. }
  166. bool IsSupportGuaranteedOpenCL_2_0(uint32_t capability, bool embedded_profile) {
  167. if (IsSupportGuaranteedOpenCL_1_2(capability, embedded_profile)) return true;
  168. switch (capability) {
  169. case SpvCapabilityDeviceEnqueue:
  170. case SpvCapabilityGenericPointer:
  171. case SpvCapabilityGroups:
  172. case SpvCapabilityPipes:
  173. return true;
  174. }
  175. return false;
  176. }
  177. bool IsSupportGuaranteedOpenCL_2_2(uint32_t capability, bool embedded_profile) {
  178. if (IsSupportGuaranteedOpenCL_2_0(capability, embedded_profile)) return true;
  179. switch (capability) {
  180. case SpvCapabilitySubgroupDispatch:
  181. case SpvCapabilityPipeStorage:
  182. return true;
  183. }
  184. return false;
  185. }
  186. bool IsSupportOptionalOpenCL_1_2(uint32_t capability) {
  187. switch (capability) {
  188. case SpvCapabilityImageBasic:
  189. case SpvCapabilityFloat64:
  190. return true;
  191. }
  192. return false;
  193. }
  194. // Checks if |capability| was enabled by extension.
  195. bool IsEnabledByExtension(ValidationState_t& _, uint32_t capability) {
  196. spv_operand_desc operand_desc = nullptr;
  197. _.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  198. &operand_desc);
  199. // operand_desc is expected to be not null, otherwise validator would have
  200. // failed at an earlier stage. This 'assert' is 'just in case'.
  201. assert(operand_desc);
  202. ExtensionSet operand_exts(operand_desc->numExtensions,
  203. operand_desc->extensions);
  204. if (operand_exts.IsEmpty()) return false;
  205. return _.HasAnyOfExtensions(operand_exts);
  206. }
  207. bool IsEnabledByCapabilityOpenCL_1_2(ValidationState_t& _,
  208. uint32_t capability) {
  209. if (_.HasCapability(SpvCapabilityImageBasic)) {
  210. switch (capability) {
  211. case SpvCapabilityLiteralSampler:
  212. case SpvCapabilitySampled1D:
  213. case SpvCapabilityImage1D:
  214. case SpvCapabilitySampledBuffer:
  215. case SpvCapabilityImageBuffer:
  216. return true;
  217. }
  218. return false;
  219. }
  220. return false;
  221. }
  222. bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _,
  223. uint32_t capability) {
  224. if (_.HasCapability(SpvCapabilityImageBasic)) {
  225. switch (capability) {
  226. case SpvCapabilityImageReadWrite:
  227. case SpvCapabilityLiteralSampler:
  228. case SpvCapabilitySampled1D:
  229. case SpvCapabilityImage1D:
  230. case SpvCapabilitySampledBuffer:
  231. case SpvCapabilityImageBuffer:
  232. return true;
  233. }
  234. return false;
  235. }
  236. return false;
  237. }
  238. } // namespace
  239. // Validates that capability declarations use operands allowed in the current
  240. // context.
  241. spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) {
  242. if (inst->opcode() != SpvOpCapability) return SPV_SUCCESS;
  243. assert(inst->operands().size() == 1);
  244. const spv_parsed_operand_t& operand = inst->operand(0);
  245. assert(operand.num_words == 1);
  246. assert(operand.offset < inst->words().size());
  247. const uint32_t capability = inst->word(operand.offset);
  248. const auto capability_str = [&_, capability]() {
  249. spv_operand_desc desc = nullptr;
  250. if (_.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  251. &desc) != SPV_SUCCESS ||
  252. !desc) {
  253. return std::string("Unknown");
  254. }
  255. return std::string(desc->name);
  256. };
  257. const auto env = _.context()->target_env;
  258. const bool opencl_embedded = env == SPV_ENV_OPENCL_EMBEDDED_1_2 ||
  259. env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  260. env == SPV_ENV_OPENCL_EMBEDDED_2_1 ||
  261. env == SPV_ENV_OPENCL_EMBEDDED_2_2;
  262. const std::string opencl_profile = opencl_embedded ? "Embedded" : "Full";
  263. if (env == SPV_ENV_VULKAN_1_0) {
  264. if (!IsSupportGuaranteedVulkan_1_0(capability) &&
  265. !IsSupportOptionalVulkan_1_0(capability) &&
  266. !IsEnabledByExtension(_, capability)) {
  267. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  268. << "Capability " << capability_str()
  269. << " is not allowed by Vulkan 1.0 specification"
  270. << " (or requires extension)";
  271. }
  272. } else if (env == SPV_ENV_VULKAN_1_1) {
  273. if (!IsSupportGuaranteedVulkan_1_1(capability) &&
  274. !IsSupportOptionalVulkan_1_1(capability) &&
  275. !IsEnabledByExtension(_, capability)) {
  276. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  277. << "Capability " << capability_str()
  278. << " is not allowed by Vulkan 1.1 specification"
  279. << " (or requires extension)";
  280. }
  281. } else if (env == SPV_ENV_VULKAN_1_2) {
  282. if (!IsSupportGuaranteedVulkan_1_2(capability) &&
  283. !IsSupportOptionalVulkan_1_2(capability) &&
  284. !IsEnabledByExtension(_, capability)) {
  285. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  286. << "Capability " << capability_str()
  287. << " is not allowed by Vulkan 1.2 specification"
  288. << " (or requires extension)";
  289. }
  290. } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) {
  291. if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) &&
  292. !IsSupportOptionalOpenCL_1_2(capability) &&
  293. !IsEnabledByExtension(_, capability) &&
  294. !IsEnabledByCapabilityOpenCL_1_2(_, capability)) {
  295. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  296. << "Capability " << capability_str()
  297. << " is not allowed by OpenCL 1.2 " << opencl_profile
  298. << " Profile specification"
  299. << " (or requires extension or capability)";
  300. }
  301. } else if (env == SPV_ENV_OPENCL_2_0 || env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  302. env == SPV_ENV_OPENCL_2_1 || env == SPV_ENV_OPENCL_EMBEDDED_2_1) {
  303. if (!IsSupportGuaranteedOpenCL_2_0(capability, opencl_embedded) &&
  304. !IsSupportOptionalOpenCL_1_2(capability) &&
  305. !IsEnabledByExtension(_, capability) &&
  306. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  307. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  308. << "Capability " << capability_str()
  309. << " is not allowed by OpenCL 2.0/2.1 " << opencl_profile
  310. << " Profile specification"
  311. << " (or requires extension or capability)";
  312. }
  313. } else if (env == SPV_ENV_OPENCL_2_2 || env == SPV_ENV_OPENCL_EMBEDDED_2_2) {
  314. if (!IsSupportGuaranteedOpenCL_2_2(capability, opencl_embedded) &&
  315. !IsSupportOptionalOpenCL_1_2(capability) &&
  316. !IsEnabledByExtension(_, capability) &&
  317. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  318. return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
  319. << "Capability " << capability_str()
  320. << " is not allowed by OpenCL 2.2 " << opencl_profile
  321. << " Profile specification"
  322. << " (or requires extension or capability)";
  323. }
  324. }
  325. return SPV_SUCCESS;
  326. }
  327. } // namespace val
  328. } // namespace spvtools