validate_capability.cpp 13 KB

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