VkPipelineFactory.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/Vulkan/VkPipelineFactory.h>
  6. #include <AnKi/Gr/Vulkan/VkGrManager.h>
  7. #include <AnKi/Gr/BackendCommon/Functions.h>
  8. #include <AnKi/Util/Tracer.h>
  9. #include <AnKi/Util/Filesystem.h>
  10. namespace anki {
  11. static NumericCVar<PtrSize> g_diskShaderCacheMaxSizeCVar(CVarSubsystem::kGr, "DiskShaderCacheMaxSize", 128_MB, 1_MB, 1_GB,
  12. "Max size of the pipeline cache file");
  13. void PipelineStateTracker::reset()
  14. {
  15. m_state.reset();
  16. m_hashes = {};
  17. m_dirty = {};
  18. m_set = {};
  19. m_shaderVertexAttributeMask.unsetAll();
  20. m_shaderColorAttachmentWritemask.unsetAll();
  21. m_fbDepth = false;
  22. m_fbStencil = false;
  23. m_rendersToSwapchain = false;
  24. m_fbColorAttachmentCount = 0;
  25. }
  26. Bool PipelineStateTracker::updateHashes()
  27. {
  28. Bool stateDirty = false;
  29. // Prog
  30. if(m_dirty.m_prog)
  31. {
  32. m_dirty.m_prog = false;
  33. stateDirty = true;
  34. m_hashes.m_prog = m_state.m_prog->getUuid();
  35. }
  36. // Vertex
  37. if(m_dirty.m_attribs.getAnySet() || m_dirty.m_vertBindings.getAnySet())
  38. {
  39. for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
  40. {
  41. if(m_shaderVertexAttributeMask.get(i))
  42. {
  43. ANKI_ASSERT(m_set.m_attribs.get(i) && "Forgot to set the attribute");
  44. Bool dirty = false;
  45. if(m_dirty.m_attribs.get(i))
  46. {
  47. m_dirty.m_attribs.unset(i);
  48. dirty = true;
  49. }
  50. const U binding = m_state.m_vertex.m_attributes[i].m_binding;
  51. ANKI_ASSERT(m_set.m_vertBindings.get(binding) && "Forgot to set a vertex binding");
  52. if(m_dirty.m_vertBindings.get(binding))
  53. {
  54. m_dirty.m_vertBindings.unset(binding);
  55. dirty = true;
  56. }
  57. if(dirty)
  58. {
  59. m_hashes.m_vertexAttribs[i] = computeHash(&m_state.m_vertex.m_attributes[i], sizeof(m_state.m_vertex.m_attributes[i]));
  60. m_hashes.m_vertexAttribs[i] =
  61. appendHash(&m_state.m_vertex.m_bindings[i], sizeof(m_state.m_vertex.m_bindings[i]), m_hashes.m_vertexAttribs[i]);
  62. stateDirty = true;
  63. }
  64. }
  65. }
  66. }
  67. // IA
  68. if(m_dirty.m_inputAssembler)
  69. {
  70. m_dirty.m_inputAssembler = false;
  71. stateDirty = true;
  72. m_hashes.m_ia = computeHash(&m_state.m_inputAssembler, sizeof(m_state.m_inputAssembler));
  73. }
  74. // Rasterizer
  75. if(m_dirty.m_rasterizer)
  76. {
  77. m_dirty.m_rasterizer = false;
  78. stateDirty = true;
  79. m_hashes.m_raster = computeHash(&m_state.m_rasterizer, sizeof(m_state.m_rasterizer));
  80. }
  81. // Depth
  82. if(m_fbDepth && m_dirty.m_depth)
  83. {
  84. m_dirty.m_depth = false;
  85. stateDirty = true;
  86. m_hashes.m_depth = computeHash(&m_state.m_depth, sizeof(m_state.m_depth));
  87. }
  88. // Stencil
  89. if(m_fbStencil && m_dirty.m_stencil)
  90. {
  91. m_dirty.m_stencil = false;
  92. stateDirty = true;
  93. m_hashes.m_stencil = computeHash(&m_state.m_stencil, sizeof(m_state.m_stencil));
  94. }
  95. // Color
  96. if(m_fbColorAttachmentCount)
  97. {
  98. ANKI_ASSERT((m_fbColorAttachmentCount == m_shaderColorAttachmentWritemask.getSetBitCount() || !m_shaderColorAttachmentWritemask)
  99. && "Shader and FB should have same attachment mask or shader mask should be zero");
  100. if(m_dirty.m_color)
  101. {
  102. m_dirty.m_color = false;
  103. m_hashes.m_color = m_state.m_color.m_alphaToCoverageEnabled ? 1 : 2;
  104. stateDirty = true;
  105. }
  106. for(U32 i = 0; i < m_fbColorAttachmentCount; ++i)
  107. {
  108. if(m_dirty.m_colAttachments.get(i))
  109. {
  110. m_dirty.m_colAttachments.unset(i);
  111. m_hashes.m_colAttachments[i] = computeHash(&m_state.m_color.m_attachments[i], sizeof(m_state.m_color.m_attachments[i]));
  112. stateDirty = true;
  113. }
  114. }
  115. }
  116. // Rpass
  117. if(m_dirty.m_rpass)
  118. {
  119. m_dirty.m_rpass = false;
  120. stateDirty = true;
  121. m_hashes.m_rpass = computeHash(m_state.m_attachmentFormats.getBegin(), m_state.m_attachmentFormats.getSizeInBytes());
  122. }
  123. return stateDirty;
  124. }
  125. void PipelineStateTracker::updateSuperHash()
  126. {
  127. Array<U64, sizeof(Hashes) / sizeof(U64)> buff;
  128. U count = 0;
  129. // Prog
  130. buff[count++] = m_hashes.m_prog;
  131. // Rpass
  132. buff[count++] = m_hashes.m_rpass;
  133. // Vertex
  134. if(!!m_shaderVertexAttributeMask)
  135. {
  136. for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
  137. {
  138. if(m_shaderVertexAttributeMask.get(i))
  139. {
  140. buff[count++] = m_hashes.m_vertexAttribs[i];
  141. }
  142. }
  143. }
  144. // IA
  145. buff[count++] = m_hashes.m_ia;
  146. // Rasterizer
  147. buff[count++] = m_hashes.m_raster;
  148. // Depth
  149. if(m_fbDepth)
  150. {
  151. buff[count++] = m_hashes.m_depth;
  152. }
  153. // Stencil
  154. if(m_fbStencil)
  155. {
  156. buff[count++] = m_hashes.m_stencil;
  157. }
  158. // Color
  159. if(m_fbColorAttachmentCount)
  160. {
  161. buff[count++] = m_hashes.m_color;
  162. for(U i = 0; i < m_fbColorAttachmentCount; ++i)
  163. {
  164. buff[count++] = m_hashes.m_colAttachments[i];
  165. }
  166. }
  167. // Super hash
  168. m_hashes.m_superHash = computeHash(&buff[0], count * sizeof(buff[0]));
  169. }
  170. const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateInfo()
  171. {
  172. VkGraphicsPipelineCreateInfo& ci = m_ci.m_ppline;
  173. ci = {};
  174. ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  175. if(m_pipelineStatisticsEnabled)
  176. {
  177. ci.flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
  178. }
  179. // Prog
  180. ci.pStages = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getShaderCreateInfos(ci.stageCount);
  181. // Vert
  182. VkPipelineVertexInputStateCreateInfo& vertCi = m_ci.m_vert;
  183. vertCi = {};
  184. vertCi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  185. vertCi.pVertexAttributeDescriptions = &m_ci.m_attribs[0];
  186. vertCi.pVertexBindingDescriptions = &m_ci.m_vertBindings[0];
  187. BitSet<U32(VertexAttributeSemantic::kCount), U8> bindingSet = {false};
  188. for(VertexAttributeSemantic semantic : EnumIterable<VertexAttributeSemantic>())
  189. {
  190. if(m_shaderVertexAttributeMask.get(semantic))
  191. {
  192. VkVertexInputAttributeDescription& attrib = m_ci.m_attribs[vertCi.vertexAttributeDescriptionCount++];
  193. attrib.binding = m_state.m_vertex.m_attributes[semantic].m_binding;
  194. attrib.format = convertFormat(m_state.m_vertex.m_attributes[semantic].m_format);
  195. attrib.location = m_semanticToVertexAttributeLocation[semantic];
  196. attrib.offset = U32(m_state.m_vertex.m_attributes[semantic].m_offset);
  197. if(!bindingSet.get(attrib.binding))
  198. {
  199. bindingSet.set(attrib.binding);
  200. VkVertexInputBindingDescription& binding = m_ci.m_vertBindings[vertCi.vertexBindingDescriptionCount++];
  201. binding.binding = attrib.binding;
  202. binding.inputRate = convertVertexStepRate(m_state.m_vertex.m_bindings[attrib.binding].m_stepRate);
  203. binding.stride = m_state.m_vertex.m_bindings[attrib.binding].m_stride;
  204. }
  205. }
  206. }
  207. ci.pVertexInputState = &vertCi;
  208. // IA
  209. VkPipelineInputAssemblyStateCreateInfo& iaCi = m_ci.m_ia;
  210. iaCi = {};
  211. iaCi.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  212. iaCi.primitiveRestartEnable = m_state.m_inputAssembler.m_primitiveRestartEnabled;
  213. iaCi.topology = convertTopology(m_state.m_inputAssembler.m_topology);
  214. ci.pInputAssemblyState = &iaCi;
  215. // Viewport
  216. VkPipelineViewportStateCreateInfo& vpCi = m_ci.m_vp;
  217. vpCi = {};
  218. vpCi.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  219. vpCi.scissorCount = 1;
  220. vpCi.viewportCount = 1;
  221. ci.pViewportState = &vpCi;
  222. // Raster
  223. VkPipelineRasterizationStateCreateInfo& rastCi = m_ci.m_rast;
  224. rastCi = {};
  225. rastCi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  226. rastCi.depthClampEnable = false;
  227. rastCi.rasterizerDiscardEnable = false;
  228. rastCi.polygonMode = convertFillMode(m_state.m_rasterizer.m_fillMode);
  229. rastCi.cullMode = convertCullMode(m_state.m_rasterizer.m_cullMode);
  230. rastCi.frontFace = (!m_rendersToSwapchain) ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE; // For viewport flip
  231. rastCi.depthBiasEnable = m_state.m_rasterizer.m_depthBiasEnabled;
  232. rastCi.lineWidth = 1.0;
  233. ci.pRasterizationState = &rastCi;
  234. if(m_state.m_rasterizer.m_rasterizationOrder != RasterizationOrder::kOrdered)
  235. {
  236. VkPipelineRasterizationStateRasterizationOrderAMD& rastOrderCi = m_ci.m_rasterOrder;
  237. rastOrderCi = {};
  238. rastOrderCi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD;
  239. rastOrderCi.rasterizationOrder = convertRasterizationOrder(m_state.m_rasterizer.m_rasterizationOrder);
  240. appendPNextList(rastCi, &rastOrderCi);
  241. }
  242. // MS
  243. VkPipelineMultisampleStateCreateInfo& msCi = m_ci.m_ms;
  244. msCi = {};
  245. msCi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  246. msCi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
  247. ci.pMultisampleState = &msCi;
  248. // DS
  249. if(m_fbDepth || m_fbStencil)
  250. {
  251. VkPipelineDepthStencilStateCreateInfo& dsCi = m_ci.m_ds;
  252. dsCi = {};
  253. dsCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
  254. if(m_fbDepth)
  255. {
  256. dsCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
  257. dsCi.depthTestEnable = m_state.m_depth.m_depthCompareFunction != CompareOperation::kAlways || m_state.m_depth.m_depthWriteEnabled;
  258. dsCi.depthWriteEnable = m_state.m_depth.m_depthWriteEnabled;
  259. dsCi.depthCompareOp = convertCompareOp(m_state.m_depth.m_depthCompareFunction);
  260. }
  261. if(m_fbStencil)
  262. {
  263. const StencilPipelineState& ss = m_state.m_stencil;
  264. dsCi.stencilTestEnable = !stencilTestDisabled(ss.m_face[0].m_stencilFailOperation, ss.m_face[0].m_stencilPassDepthFailOperation,
  265. ss.m_face[0].m_stencilPassDepthPassOperation, ss.m_face[0].m_compareFunction)
  266. || !stencilTestDisabled(ss.m_face[1].m_stencilFailOperation, ss.m_face[1].m_stencilPassDepthFailOperation,
  267. ss.m_face[1].m_stencilPassDepthPassOperation, ss.m_face[1].m_compareFunction);
  268. dsCi.front.failOp = convertStencilOp(ss.m_face[0].m_stencilFailOperation);
  269. dsCi.front.passOp = convertStencilOp(ss.m_face[0].m_stencilPassDepthPassOperation);
  270. dsCi.front.depthFailOp = convertStencilOp(ss.m_face[0].m_stencilPassDepthFailOperation);
  271. dsCi.front.compareOp = convertCompareOp(ss.m_face[0].m_compareFunction);
  272. dsCi.back.failOp = convertStencilOp(ss.m_face[1].m_stencilFailOperation);
  273. dsCi.back.passOp = convertStencilOp(ss.m_face[1].m_stencilPassDepthPassOperation);
  274. dsCi.back.depthFailOp = convertStencilOp(ss.m_face[1].m_stencilPassDepthFailOperation);
  275. dsCi.back.compareOp = convertCompareOp(ss.m_face[1].m_compareFunction);
  276. }
  277. ci.pDepthStencilState = &dsCi;
  278. }
  279. // Color/blend
  280. if(m_fbColorAttachmentCount)
  281. {
  282. VkPipelineColorBlendStateCreateInfo& colCi = m_ci.m_color;
  283. colCi = {};
  284. colCi.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  285. colCi.attachmentCount = m_fbColorAttachmentCount;
  286. colCi.pAttachments = &m_ci.m_colAttachments[0];
  287. for(U i = 0; i < colCi.attachmentCount; ++i)
  288. {
  289. VkPipelineColorBlendAttachmentState& out = m_ci.m_colAttachments[i];
  290. const ColorAttachmentState& in = m_state.m_color.m_attachments[i];
  291. out.blendEnable = !blendingDisabled(in.m_srcBlendFactorRgb, in.m_dstBlendFactorRgb, in.m_srcBlendFactorA, in.m_dstBlendFactorA,
  292. in.m_blendFunctionRgb, in.m_blendFunctionA);
  293. out.srcColorBlendFactor = convertBlendFactor(in.m_srcBlendFactorRgb);
  294. out.dstColorBlendFactor = convertBlendFactor(in.m_dstBlendFactorRgb);
  295. out.srcAlphaBlendFactor = convertBlendFactor(in.m_srcBlendFactorA);
  296. out.dstAlphaBlendFactor = convertBlendFactor(in.m_dstBlendFactorA);
  297. out.colorBlendOp = convertBlendOperation(in.m_blendFunctionRgb);
  298. out.alphaBlendOp = convertBlendOperation(in.m_blendFunctionA);
  299. out.colorWriteMask = convertColorWriteMask(in.m_channelWriteMask);
  300. }
  301. ci.pColorBlendState = &colCi;
  302. }
  303. // Dyn state
  304. VkPipelineDynamicStateCreateInfo& dynCi = m_ci.m_dyn;
  305. dynCi = {};
  306. dynCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
  307. // Renderpass related (Dynamic rendering)
  308. VkPipelineRenderingCreateInfoKHR& dynRendering = m_ci.m_dynamicRendering;
  309. dynRendering = {};
  310. dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
  311. dynRendering.colorAttachmentCount = m_fbColorAttachmentCount;
  312. dynRendering.pColorAttachmentFormats = m_ci.m_dynamicRenderingAttachmentFormats.getBegin();
  313. for(U i = 0; i < m_fbColorAttachmentCount; ++i)
  314. {
  315. m_ci.m_dynamicRenderingAttachmentFormats[i] = convertFormat(m_state.m_attachmentFormats[i]);
  316. }
  317. if(m_fbDepth)
  318. {
  319. dynRendering.depthAttachmentFormat = convertFormat(m_state.m_attachmentFormats[kMaxColorRenderTargets]);
  320. }
  321. if(m_fbStencil)
  322. {
  323. dynRendering.stencilAttachmentFormat = convertFormat(m_state.m_attachmentFormats[kMaxColorRenderTargets]);
  324. }
  325. appendPNextList(ci, &m_ci.m_dynamicRendering);
  326. // Almost all state is dynamic. Depth bias is static
  327. static constexpr Array<VkDynamicState, 10> kDyn = {
  328. {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS,
  329. VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_LINE_WIDTH,
  330. VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR}};
  331. dynCi.dynamicStateCount = (m_vrsCapable) ? kDyn.getSize() : (kDyn.getSize() - 1);
  332. dynCi.pDynamicStates = &kDyn[0];
  333. ci.pDynamicState = &dynCi;
  334. // The rest
  335. ci.layout = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getPipelineLayout().getHandle();
  336. ci.subpass = 0;
  337. return ci;
  338. }
  339. class PipelineFactory::PipelineInternal
  340. {
  341. public:
  342. VkPipeline m_handle = VK_NULL_HANDLE;
  343. };
  344. class PipelineFactory::Hasher
  345. {
  346. public:
  347. U64 operator()(U64 h)
  348. {
  349. return h;
  350. }
  351. };
  352. PipelineFactory::PipelineFactory()
  353. {
  354. }
  355. PipelineFactory::~PipelineFactory()
  356. {
  357. }
  358. void PipelineFactory::destroy()
  359. {
  360. for(auto it : m_pplines)
  361. {
  362. if(it.m_handle)
  363. {
  364. vkDestroyPipeline(getVkDevice(), it.m_handle, nullptr);
  365. }
  366. }
  367. m_pplines.destroy();
  368. }
  369. void PipelineFactory::getOrCreatePipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty)
  370. {
  371. ANKI_TRACE_SCOPED_EVENT(VkPipelineGetOrCreate);
  372. U64 hash;
  373. state.flush(hash, stateDirty);
  374. if(!stateDirty) [[unlikely]]
  375. {
  376. ppline.m_handle = VK_NULL_HANDLE;
  377. return;
  378. }
  379. // Check if ppline exists
  380. {
  381. RLockGuard<RWMutex> lock(m_pplinesMtx);
  382. auto it = m_pplines.find(hash);
  383. if(it != m_pplines.getEnd())
  384. {
  385. ppline.m_handle = (*it).m_handle;
  386. ANKI_TRACE_INC_COUNTER(VkPipelineCacheHit, 1);
  387. return;
  388. }
  389. }
  390. // Doesnt exist. Need to create it
  391. WLockGuard<RWMutex> lock(m_pplinesMtx);
  392. // Check again
  393. auto it = m_pplines.find(hash);
  394. if(it != m_pplines.getEnd())
  395. {
  396. ppline.m_handle = (*it).m_handle;
  397. return;
  398. }
  399. // Create it for real
  400. PipelineInternal pp;
  401. const VkGraphicsPipelineCreateInfo& ci = state.updatePipelineCreateInfo();
  402. {
  403. ANKI_TRACE_SCOPED_EVENT(VkPipelineCreate);
  404. #if ANKI_PLATFORM_MOBILE
  405. if(PipelineCache::getSingleton().m_globalCreatePipelineMtx)
  406. {
  407. PipelineCache::getSingleton().m_globalCreatePipelineMtx->lock();
  408. }
  409. #endif
  410. ANKI_VK_CHECKF(vkCreateGraphicsPipelines(getVkDevice(), PipelineCache::getSingleton().m_cacheHandle, 1, &ci, nullptr, &pp.m_handle));
  411. #if ANKI_PLATFORM_MOBILE
  412. if(PipelineCache::getSingleton().m_globalCreatePipelineMtx)
  413. {
  414. PipelineCache::getSingleton().m_globalCreatePipelineMtx->unlock();
  415. }
  416. #endif
  417. }
  418. ANKI_TRACE_INC_COUNTER(VkPipelineCacheMiss, 1);
  419. m_pplines.emplace(hash, pp);
  420. ppline.m_handle = pp.m_handle;
  421. // Print shader info
  422. getGrManagerImpl().printPipelineShaderInfo(pp.m_handle, state.m_state.m_prog->getName(), hash);
  423. }
  424. Error PipelineCache::init(CString cacheDir)
  425. {
  426. ANKI_ASSERT(cacheDir);
  427. m_dumpSize = g_diskShaderCacheMaxSizeCVar.get();
  428. m_dumpFilename.sprintf("%s/VkPipelineCache", cacheDir.cstr());
  429. // Try read the pipeline cache file.
  430. GrDynamicArray<U8, PtrSize> diskDump;
  431. if(fileExists(m_dumpFilename.toCString()))
  432. {
  433. File file;
  434. ANKI_CHECK(file.open(m_dumpFilename.toCString(), FileOpenFlag::kBinary | FileOpenFlag::kRead));
  435. const PtrSize diskDumpSize = file.getSize();
  436. if(diskDumpSize <= sizeof(U8) * VK_UUID_SIZE)
  437. {
  438. ANKI_VK_LOGI("Pipeline cache dump appears to be empty: %s", &m_dumpFilename[0]);
  439. }
  440. else
  441. {
  442. // Get current pipeline UUID and compare it with the cache's
  443. VkPhysicalDeviceProperties props;
  444. vkGetPhysicalDeviceProperties(getGrManagerImpl().getPhysicalDevice(), &props);
  445. Array<U8, VK_UUID_SIZE> cacheUuid;
  446. ANKI_CHECK(file.read(&cacheUuid[0], VK_UUID_SIZE));
  447. if(memcmp(&cacheUuid[0], &props.pipelineCacheUUID[0], VK_UUID_SIZE) != 0)
  448. {
  449. ANKI_VK_LOGI("Pipeline cache dump is not compatible with the current device: %s", &m_dumpFilename[0]);
  450. }
  451. else
  452. {
  453. diskDump.resize(diskDumpSize - VK_UUID_SIZE);
  454. ANKI_CHECK(file.read(&diskDump[0], diskDumpSize - VK_UUID_SIZE));
  455. }
  456. }
  457. }
  458. else
  459. {
  460. ANKI_VK_LOGI("Pipeline cache dump not found: %s", &m_dumpFilename[0]);
  461. }
  462. // Create the cache
  463. VkPipelineCacheCreateInfo ci = {};
  464. ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
  465. if(diskDump.getSize())
  466. {
  467. ANKI_VK_LOGI("Will load %zu bytes of pipeline cache", diskDump.getSize());
  468. ci.initialDataSize = diskDump.getSize();
  469. ci.pInitialData = &diskDump[0];
  470. }
  471. ANKI_VK_CHECK(vkCreatePipelineCache(getVkDevice(), &ci, nullptr, &m_cacheHandle));
  472. #if ANKI_PLATFORM_MOBILE
  473. ANKI_ASSERT(GrManager::getSingleton().getDeviceCapabilities() != GpuVendor::kNone);
  474. if(GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kQualcomm)
  475. {
  476. // Calling vkCreateGraphicsPipeline from multiple threads crashes qualcomm's compiler
  477. ANKI_VK_LOGI("Enabling workaround for vkCreateGraphicsPipeline crashing when called from multiple threads");
  478. m_globalCreatePipelineMtx = anki::newInstance<Mutex>(GrMemoryPool::getSingleton());
  479. }
  480. #endif
  481. return Error::kNone;
  482. }
  483. void PipelineCache::destroy()
  484. {
  485. const Error err = destroyInternal();
  486. if(err)
  487. {
  488. ANKI_VK_LOGE("An error occurred while storing the pipeline cache to disk. Will ignore");
  489. }
  490. m_dumpFilename.destroy();
  491. }
  492. Error PipelineCache::destroyInternal()
  493. {
  494. #if ANKI_PLATFORM_MOBILE
  495. deleteInstance(GrMemoryPool::getSingleton(), m_globalCreatePipelineMtx);
  496. #endif
  497. if(m_cacheHandle)
  498. {
  499. // Get size of cache
  500. size_t size = 0;
  501. ANKI_VK_CHECK(vkGetPipelineCacheData(getVkDevice(), m_cacheHandle, &size, nullptr));
  502. size = min(size, m_dumpSize);
  503. if(size > 0)
  504. {
  505. // Read cache
  506. GrDynamicArray<U8, PtrSize> cacheData;
  507. cacheData.resize(size);
  508. ANKI_VK_CHECK(vkGetPipelineCacheData(getVkDevice(), m_cacheHandle, &size, &cacheData[0]));
  509. // Write file
  510. File file;
  511. ANKI_CHECK(file.open(&m_dumpFilename[0], FileOpenFlag::kBinary | FileOpenFlag::kWrite));
  512. VkPhysicalDeviceProperties props;
  513. vkGetPhysicalDeviceProperties(getGrManagerImpl().getPhysicalDevice(), &props);
  514. ANKI_CHECK(file.write(&props.pipelineCacheUUID[0], VK_UUID_SIZE));
  515. ANKI_CHECK(file.write(&cacheData[0], size));
  516. ANKI_VK_LOGI("Dumped %zu bytes of the pipeline cache", size);
  517. }
  518. // Destroy cache
  519. vkDestroyPipelineCache(getVkDevice(), m_cacheHandle, nullptr);
  520. m_cacheHandle = VK_NULL_HANDLE;
  521. }
  522. return Error::kNone;
  523. }
  524. } // end namespace anki