You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

pipelinecache.cpp 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "pipelinecache.h"
  15. #include "gpu.h"
  16. namespace ncnn {
  17. #if NCNN_VULKAN
  18. // https://en.wikipedia.org/wiki/MurmurHash
  19. static uint32_t murmur3_32(const uint32_t* data, int size)
  20. {
  21. uint32_t h = 0;
  22. for (int i = 0; i < size; i++)
  23. {
  24. uint32_t k = *data++;
  25. k *= 0xcc9e2d51;
  26. k = (k << 15) | (k >> (32 - 15));
  27. k *= 0x1b873593;
  28. h ^= k;
  29. h = (h << 13) | (h >> (32 - 13));
  30. h = (h * 5) + 0xe6546b64;
  31. }
  32. h ^= size * 4;
  33. h ^= h >> 16;
  34. h *= 0x85ebca6b;
  35. h ^= h >> 13;
  36. h *= 0xc2b2ae35;
  37. h ^= h >> 16;
  38. return h;
  39. }
  40. // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
  41. static uint32_t fnv1a_32(const uint8_t* data, int size)
  42. {
  43. uint32_t h = 0x811c9dc5;
  44. for (int i = 0; i < size; i++)
  45. {
  46. h ^= (uint32_t)*data++;
  47. h *= 0x01000193;
  48. }
  49. return h;
  50. }
  51. PipelineCache::pipeline_cache_digest::pipeline_cache_digest(const uint32_t* spv_data, size_t spv_data_size, const std::vector<vk_specialization_type>& specializations,
  52. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z)
  53. {
  54. spv_data_murmur3 = murmur3_32(spv_data, spv_data_size / 4);
  55. // encode opt
  56. opt_local_size_bits[0] = 0;
  57. // encode local_size
  58. opt_local_size_bits[1] = local_size_x;
  59. opt_local_size_bits[2] = local_size_y;
  60. opt_local_size_bits[3] = local_size_z;
  61. // encode specializations
  62. const int specialization_count = specializations.size();
  63. specializations_murmur3 = murmur3_32((const uint32_t*)specializations.data(), specialization_count);
  64. specializations_fnv1a = fnv1a_32((const uint8_t*)specializations.data(), specialization_count * sizeof(vk_specialization_type));
  65. }
  66. PipelineCache::pipeline_cache_digest::pipeline_cache_digest(int _shader_type_index, const Option& opt, const std::vector<vk_specialization_type>& specializations,
  67. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z)
  68. {
  69. shader_type_index = _shader_type_index;
  70. // encode opt
  71. opt_local_size_bits[0] = opt.use_image_storage << 7
  72. | opt.use_fp16_packed << 6
  73. | opt.use_fp16_storage << 5
  74. | opt.use_fp16_arithmetic << 4
  75. | opt.use_int8_storage << 3
  76. | opt.use_int8_arithmetic << 2;
  77. // encode local_size
  78. opt_local_size_bits[1] = local_size_x;
  79. opt_local_size_bits[2] = local_size_y;
  80. opt_local_size_bits[3] = local_size_z;
  81. // encode specializations
  82. const int specialization_count = specializations.size();
  83. specializations_murmur3 = murmur3_32((const uint32_t*)specializations.data(), specialization_count);
  84. specializations_fnv1a = fnv1a_32((const uint8_t*)specializations.data(), specialization_count * sizeof(vk_specialization_type));
  85. }
  86. PipelineCache::PipelineCache(const VulkanDevice* _vkdev)
  87. : vkdev(_vkdev)
  88. {
  89. }
  90. PipelineCache::~PipelineCache()
  91. {
  92. clear();
  93. }
  94. void PipelineCache::clear()
  95. {
  96. MutexLockGuard lock(cache_lock);
  97. for (size_t i = 0; i < cache_artifacts.size(); i++)
  98. {
  99. const pipeline_cache_artifact& cc = cache_artifacts[i];
  100. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  101. {
  102. if (cc.descriptor_update_template)
  103. {
  104. vkdev->vkDestroyDescriptorUpdateTemplateKHR(vkdev->vkdevice(), cc.descriptor_update_template, 0);
  105. }
  106. }
  107. if (cc.pipeline)
  108. {
  109. vkDestroyPipeline(vkdev->vkdevice(), cc.pipeline, 0);
  110. }
  111. if (cc.pipeline_layout)
  112. {
  113. vkDestroyPipelineLayout(vkdev->vkdevice(), cc.pipeline_layout, 0);
  114. }
  115. if (cc.descriptorset_layout)
  116. {
  117. vkDestroyDescriptorSetLayout(vkdev->vkdevice(), cc.descriptorset_layout, 0);
  118. }
  119. if (cc.shader_module)
  120. {
  121. vkDestroyShaderModule(vkdev->vkdevice(), cc.shader_module, 0);
  122. }
  123. }
  124. cache_digests.clear();
  125. cache_artifacts.clear();
  126. }
  127. int PipelineCache::get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector<vk_specialization_type>& specializations,
  128. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  129. VkShaderModule* _shader_module,
  130. VkDescriptorSetLayout* descriptorset_layout,
  131. VkPipelineLayout* pipeline_layout,
  132. VkPipeline* pipeline,
  133. VkDescriptorUpdateTemplateKHR* descriptor_update_template,
  134. ShaderInfo& shader_info) const
  135. {
  136. MutexLockGuard lock(cache_lock);
  137. pipeline_cache_digest key(spv_data, spv_data_size, specializations, local_size_x, local_size_y, local_size_z);
  138. if (!vkdev->info.bug_corrupted_online_pipeline_cache)
  139. {
  140. // find cache
  141. for (size_t i = 0; i < cache_digests.size(); i++)
  142. {
  143. if (cache_digests[i] != key)
  144. continue;
  145. // hit cache
  146. const pipeline_cache_artifact& cc = cache_artifacts[i];
  147. *_shader_module = cc.shader_module;
  148. *descriptorset_layout = cc.descriptorset_layout;
  149. *pipeline_layout = cc.pipeline_layout;
  150. *pipeline = cc.pipeline;
  151. *descriptor_update_template = cc.descriptor_update_template;
  152. shader_info = cc.shader_info;
  153. // NCNN_LOGE("get_pipeline hit %d", last_digest_index);
  154. return 0;
  155. }
  156. }
  157. int ret = 0;
  158. ret = resolve_shader_info(spv_data, spv_data_size, shader_info);
  159. if (ret != 0)
  160. {
  161. NCNN_LOGE("resolve_shader_info failed %d", ret);
  162. return -1;
  163. }
  164. VkShaderModule shader_module = vkdev->compile_shader_module(spv_data, spv_data_size, local_size_x, local_size_y, local_size_z);
  165. if (!shader_module)
  166. {
  167. NCNN_LOGE("create_shader_module failed");
  168. return -1;
  169. }
  170. ret = new_pipeline(shader_module, shader_info, specializations, descriptorset_layout, pipeline_layout, pipeline, descriptor_update_template);
  171. if (ret != 0)
  172. {
  173. NCNN_LOGE("new_pipeline failed");
  174. vkDestroyShaderModule(vkdev->vkdevice(), shader_module, 0);
  175. return -1;
  176. }
  177. *_shader_module = shader_module;
  178. // save to cache
  179. {
  180. pipeline_cache_artifact cc;
  181. cc.shader_module = *_shader_module;
  182. cc.descriptorset_layout = *descriptorset_layout;
  183. cc.pipeline_layout = *pipeline_layout;
  184. cc.pipeline = *pipeline;
  185. cc.descriptor_update_template = *descriptor_update_template;
  186. cc.shader_info = shader_info;
  187. cache_digests.push_back(key);
  188. cache_artifacts.push_back(cc);
  189. }
  190. // NCNN_LOGE("new_pipeline %d", last_digest_index);
  191. return 0;
  192. }
  193. int PipelineCache::get_pipeline(int shader_type_index, const Option& opt, const std::vector<vk_specialization_type>& specializations,
  194. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  195. VkShaderModule* _shader_module,
  196. VkDescriptorSetLayout* descriptorset_layout,
  197. VkPipelineLayout* pipeline_layout,
  198. VkPipeline* pipeline,
  199. VkDescriptorUpdateTemplateKHR* descriptor_update_template,
  200. ShaderInfo& shader_info) const
  201. {
  202. MutexLockGuard lock(cache_lock);
  203. pipeline_cache_digest key(shader_type_index, opt, specializations, local_size_x, local_size_y, local_size_z);
  204. if (!vkdev->info.bug_corrupted_online_pipeline_cache)
  205. {
  206. // find cache
  207. for (size_t i = 0; i < cache_digests.size(); i++)
  208. {
  209. if (cache_digests[i] != key)
  210. continue;
  211. // hit cache
  212. const pipeline_cache_artifact& cc = cache_artifacts[i];
  213. *_shader_module = cc.shader_module;
  214. *descriptorset_layout = cc.descriptorset_layout;
  215. *pipeline_layout = cc.pipeline_layout;
  216. *pipeline = cc.pipeline;
  217. *descriptor_update_template = cc.descriptor_update_template;
  218. shader_info = cc.shader_info;
  219. // NCNN_LOGE("get_pipeline hit %d", last_digest_index);
  220. return 0;
  221. }
  222. }
  223. int ret = 0;
  224. // create new pipeline
  225. VkShaderModule shader_module = 0;
  226. ret = create_shader_module(shader_type_index, opt, local_size_x, local_size_y, local_size_z, &shader_module, shader_info);
  227. if (ret != 0)
  228. {
  229. NCNN_LOGE("create_shader_module failed");
  230. return -1;
  231. }
  232. ret = new_pipeline(shader_module, shader_info, specializations, descriptorset_layout, pipeline_layout, pipeline, descriptor_update_template);
  233. if (ret != 0)
  234. {
  235. NCNN_LOGE("new_pipeline failed");
  236. vkDestroyShaderModule(vkdev->vkdevice(), shader_module, 0);
  237. return -1;
  238. }
  239. *_shader_module = shader_module;
  240. // save to cache
  241. {
  242. pipeline_cache_artifact cc;
  243. cc.shader_module = *_shader_module;
  244. cc.descriptorset_layout = *descriptorset_layout;
  245. cc.pipeline_layout = *pipeline_layout;
  246. cc.pipeline = *pipeline;
  247. cc.descriptor_update_template = *descriptor_update_template;
  248. cc.shader_info = shader_info;
  249. cache_digests.push_back(key);
  250. cache_artifacts.push_back(cc);
  251. }
  252. // NCNN_LOGE("new_pipeline %d", last_digest_index);
  253. return 0;
  254. }
  255. int PipelineCache::create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  256. VkShaderModule* _shader_module, ShaderInfo& si) const
  257. {
  258. #if NCNN_VULKAN_ONLINE_SPIRV
  259. std::vector<uint32_t> spirv;
  260. int retc = compile_spirv_module(shader_type_index, opt, spirv);
  261. if (retc != 0)
  262. {
  263. NCNN_LOGE("compile_spirv_module failed %d", retc);
  264. return -1;
  265. }
  266. const uint32_t* spv_data = spirv.data();
  267. size_t spv_data_size = spirv.size() * 4;
  268. int ret = resolve_shader_info(spv_data, spv_data_size, si);
  269. if (ret != 0)
  270. {
  271. NCNN_LOGE("resolve_shader_info failed %d", ret);
  272. return -1;
  273. }
  274. VkShaderModule shader_module = vkdev->compile_shader_module(spv_data, spv_data_size, local_size_x, local_size_y, local_size_z);
  275. #else // NCNN_VULKAN_ONLINE_SPIRV
  276. // ncnn_add_shader cmake macro
  277. // 0 = fp32
  278. // 1 = fp16p
  279. // 2 = fp16pa
  280. // 3 = fp16s
  281. // 4 = fp16sa
  282. // 5 = image
  283. // 6 = image_fp16p
  284. // 7 = image_fp16pa
  285. // 8 = image_fp16s
  286. // 9 = image_fp16sa
  287. if (!vkdev->info.bug_layout_binding_id_alias && opt.use_image_storage && vkdev->info.support_fp16_storage && opt.use_fp16_storage && vkdev->info.support_fp16_arithmetic && opt.use_fp16_arithmetic)
  288. {
  289. shader_type_index += 9;
  290. }
  291. else if (!vkdev->info.bug_layout_binding_id_alias && opt.use_image_storage && vkdev->info.support_fp16_packed && opt.use_fp16_packed && vkdev->info.support_fp16_arithmetic && opt.use_fp16_arithmetic)
  292. {
  293. shader_type_index += 7;
  294. }
  295. else if (!vkdev->info.bug_layout_binding_id_alias && opt.use_image_storage && vkdev->info.support_fp16_storage && opt.use_fp16_storage)
  296. {
  297. shader_type_index += 8;
  298. }
  299. else if (!vkdev->info.bug_layout_binding_id_alias && opt.use_image_storage && vkdev->info.support_fp16_packed && opt.use_fp16_packed)
  300. {
  301. shader_type_index += 6;
  302. }
  303. else if (!vkdev->info.bug_layout_binding_id_alias && opt.use_image_storage)
  304. {
  305. shader_type_index += 5;
  306. }
  307. else if (vkdev->info.support_fp16_storage && opt.use_fp16_storage && vkdev->info.support_fp16_arithmetic && opt.use_fp16_arithmetic)
  308. {
  309. shader_type_index += 4;
  310. }
  311. else if (vkdev->info.support_fp16_packed && opt.use_fp16_packed && vkdev->info.support_fp16_arithmetic && opt.use_fp16_arithmetic)
  312. {
  313. shader_type_index += 2;
  314. }
  315. else if (vkdev->info.support_fp16_storage && opt.use_fp16_storage)
  316. {
  317. shader_type_index += 3;
  318. }
  319. else if (vkdev->info.support_fp16_packed && opt.use_fp16_packed)
  320. {
  321. shader_type_index += 1;
  322. }
  323. si = get_shader_info(shader_type_index);
  324. VkShaderModule shader_module = vkdev->create_shader_module(shader_type_index, local_size_x, local_size_y, local_size_z);
  325. #endif // NCNN_VULKAN_ONLINE_SPIRV
  326. if (!shader_module)
  327. {
  328. NCNN_LOGE("create_shader_module failed");
  329. return -1;
  330. }
  331. *_shader_module = shader_module;
  332. return 0;
  333. }
  334. int PipelineCache::new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector<vk_specialization_type>& specializations,
  335. VkDescriptorSetLayout* _descriptorset_layout,
  336. VkPipelineLayout* _pipeline_layout,
  337. VkPipeline* _pipeline,
  338. VkDescriptorUpdateTemplateKHR* _descriptor_update_template) const
  339. {
  340. int ret = 0;
  341. VkDescriptorSetLayout descriptorset_layout = 0;
  342. VkPipelineLayout pipeline_layout = 0;
  343. VkPipeline pipeline = 0;
  344. VkDescriptorUpdateTemplateKHR descriptor_update_template = 0;
  345. // create new pipeline
  346. if ((int)specializations.size() != shader_info.specialization_count)
  347. {
  348. NCNN_LOGE("pipeline specialization count mismatch, expect %d but got %d", shader_info.specialization_count, (int)specializations.size());
  349. goto ERROR_PipelineCache;
  350. }
  351. ret = vkdev->create_descriptorset_layout(shader_info.binding_count, shader_info.binding_types, &descriptorset_layout);
  352. if (ret != 0)
  353. goto ERROR_PipelineCache;
  354. ret = vkdev->create_pipeline_layout(shader_info.push_constant_count, descriptorset_layout, &pipeline_layout);
  355. if (ret != 0)
  356. goto ERROR_PipelineCache;
  357. ret = vkdev->create_pipeline(shader_module, pipeline_layout, specializations, &pipeline);
  358. if (ret != 0)
  359. goto ERROR_PipelineCache;
  360. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  361. {
  362. ret = vkdev->create_descriptor_update_template(shader_info.binding_count, shader_info.binding_types, descriptorset_layout, pipeline_layout, &descriptor_update_template);
  363. if (ret != 0)
  364. goto ERROR_PipelineCache;
  365. }
  366. *_descriptorset_layout = descriptorset_layout;
  367. *_pipeline_layout = pipeline_layout;
  368. *_pipeline = pipeline;
  369. *_descriptor_update_template = descriptor_update_template;
  370. return 0;
  371. ERROR_PipelineCache:
  372. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  373. {
  374. if (descriptor_update_template)
  375. {
  376. vkdev->vkDestroyDescriptorUpdateTemplateKHR(vkdev->vkdevice(), descriptor_update_template, 0);
  377. }
  378. }
  379. if (pipeline)
  380. {
  381. vkDestroyPipeline(vkdev->vkdevice(), pipeline, 0);
  382. }
  383. if (pipeline_layout)
  384. {
  385. vkDestroyPipelineLayout(vkdev->vkdevice(), pipeline_layout, 0);
  386. }
  387. if (descriptorset_layout)
  388. {
  389. vkDestroyDescriptorSetLayout(vkdev->vkdevice(), descriptorset_layout, 0);
  390. }
  391. return -1;
  392. }
  393. #endif // NCNN_VULKAN
  394. } // namespace ncnn