RenderGraph.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697
  1. // Copyright (C) 2009-2021, 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/RenderGraph.h>
  6. #include <AnKi/Gr/GrManager.h>
  7. #include <AnKi/Gr/Texture.h>
  8. #include <AnKi/Gr/Sampler.h>
  9. #include <AnKi/Gr/Framebuffer.h>
  10. #include <AnKi/Gr/CommandBuffer.h>
  11. #include <AnKi/Util/Tracer.h>
  12. #include <AnKi/Util/BitSet.h>
  13. #include <AnKi/Util/File.h>
  14. #include <AnKi/Util/StringList.h>
  15. #include <AnKi/Util/HighRezTimer.h>
  16. namespace anki
  17. {
  18. #define ANKI_DBG_RENDER_GRAPH 0
  19. static inline U32 getTextureSurfOrVolCount(const TexturePtr& tex)
  20. {
  21. return tex->getMipmapCount() * tex->getLayerCount() * (textureTypeIsCube(tex->getTextureType()) ? 6 : 1);
  22. }
  23. /// Contains some extra things for render targets.
  24. class RenderGraph::RT
  25. {
  26. public:
  27. DynamicArray<TextureUsageBit> m_surfOrVolUsages;
  28. DynamicArray<U16> m_lastBatchThatTransitionedIt;
  29. TexturePtr m_texture; ///< Hold a reference.
  30. Bool m_imported;
  31. };
  32. /// Same as RT but for buffers.
  33. class RenderGraph::Buffer
  34. {
  35. public:
  36. BufferUsageBit m_usage;
  37. BufferPtr m_buffer; ///< Hold a reference.
  38. PtrSize m_offset;
  39. PtrSize m_range;
  40. };
  41. class RenderGraph::AS
  42. {
  43. public:
  44. AccelerationStructureUsageBit m_usage;
  45. AccelerationStructurePtr m_as; ///< Hold a reference.
  46. };
  47. /// Pipeline barrier.
  48. class RenderGraph::TextureBarrier
  49. {
  50. public:
  51. U32 m_idx;
  52. TextureUsageBit m_usageBefore;
  53. TextureUsageBit m_usageAfter;
  54. TextureSurfaceInfo m_surface;
  55. TextureBarrier(U32 rtIdx, TextureUsageBit usageBefore, TextureUsageBit usageAfter, const TextureSurfaceInfo& surf)
  56. : m_idx(rtIdx)
  57. , m_usageBefore(usageBefore)
  58. , m_usageAfter(usageAfter)
  59. , m_surface(surf)
  60. {
  61. }
  62. };
  63. /// Pipeline barrier.
  64. class RenderGraph::BufferBarrier
  65. {
  66. public:
  67. U32 m_idx;
  68. BufferUsageBit m_usageBefore;
  69. BufferUsageBit m_usageAfter;
  70. BufferBarrier(U32 buffIdx, BufferUsageBit usageBefore, BufferUsageBit usageAfter)
  71. : m_idx(buffIdx)
  72. , m_usageBefore(usageBefore)
  73. , m_usageAfter(usageAfter)
  74. {
  75. }
  76. };
  77. /// Pipeline barrier.
  78. class RenderGraph::ASBarrier
  79. {
  80. public:
  81. U32 m_idx;
  82. AccelerationStructureUsageBit m_usageBefore;
  83. AccelerationStructureUsageBit m_usageAfter;
  84. ASBarrier(U32 asIdx, AccelerationStructureUsageBit usageBefore, AccelerationStructureUsageBit usageAfter)
  85. : m_idx(asIdx)
  86. , m_usageBefore(usageBefore)
  87. , m_usageAfter(usageAfter)
  88. {
  89. }
  90. };
  91. /// Contains some extra things the RenderPassBase cannot hold.
  92. class RenderGraph::Pass
  93. {
  94. public:
  95. // WARNING!!!!!: Whatever you put here needs manual destruction in RenderGraph::reset()
  96. DynamicArray<U32> m_dependsOn;
  97. DynamicArray<RenderPassDependency::TextureInfo> m_consumedTextures;
  98. Function<void(RenderPassWorkContext&)> m_callback;
  99. DynamicArray<CommandBufferPtr> m_secondLevelCmdbs;
  100. /// Will reuse the m_secondLevelCmdbInitInfo.m_framebuffer to get the framebuffer.
  101. CommandBufferInitInfo m_secondLevelCmdbInitInfo;
  102. Array<U32, 4> m_fbRenderArea;
  103. Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS> m_colorUsages = {}; ///< For beginRender pass
  104. TextureUsageBit m_dsUsage = TextureUsageBit::NONE; ///< For beginRender pass
  105. U32 m_batchIdx ANKI_DEBUG_CODE(= MAX_U32);
  106. Bool m_drawsToPresentable = false;
  107. FramebufferPtr& fb()
  108. {
  109. return m_secondLevelCmdbInitInfo.m_framebuffer;
  110. }
  111. const FramebufferPtr& fb() const
  112. {
  113. return m_secondLevelCmdbInitInfo.m_framebuffer;
  114. }
  115. };
  116. /// A batch of render passes. These passes can run in parallel.
  117. /// @warning It's POD. Destructor won't be called.
  118. class RenderGraph::Batch
  119. {
  120. public:
  121. DynamicArray<U32> m_passIndices;
  122. DynamicArray<TextureBarrier> m_textureBarriersBefore;
  123. DynamicArray<BufferBarrier> m_bufferBarriersBefore;
  124. DynamicArray<ASBarrier> m_asBarriersBefore;
  125. CommandBuffer* m_cmdb; ///< Someone else holds the ref already so have a ptr here.
  126. };
  127. /// The RenderGraph build context.
  128. class RenderGraph::BakeContext
  129. {
  130. public:
  131. StackAllocator<U8> m_alloc;
  132. DynamicArray<Pass> m_passes;
  133. BitSet<MAX_RENDER_GRAPH_PASSES, U64> m_passIsInBatch{false};
  134. DynamicArray<Batch> m_batches;
  135. DynamicArray<RT> m_rts;
  136. DynamicArray<Buffer> m_buffers;
  137. DynamicArray<AS> m_as;
  138. DynamicArray<CommandBufferPtr> m_graphicsCmdbs;
  139. Bool m_gatherStatistics = false;
  140. BakeContext(const StackAllocator<U8>& alloc)
  141. : m_alloc(alloc)
  142. {
  143. }
  144. };
  145. void FramebufferDescription::bake()
  146. {
  147. ANKI_ASSERT(m_hash == 0 && "Already baked");
  148. m_hash = 0;
  149. ANKI_ASSERT(m_colorAttachmentCount > 0 || !!m_depthStencilAttachment.m_aspect);
  150. // First the depth attachments
  151. if(m_colorAttachmentCount)
  152. {
  153. ANKI_BEGIN_PACKED_STRUCT
  154. struct ColorAttachment
  155. {
  156. TextureSurfaceInfo m_surf;
  157. U32 m_loadOp;
  158. U32 m_storeOp;
  159. Array<U32, 4> m_clearColor;
  160. };
  161. ANKI_END_PACKED_STRUCT
  162. static_assert(sizeof(ColorAttachment) == 4 * (4 + 1 + 1 + 4), "Wrong size");
  163. Array<ColorAttachment, MAX_COLOR_ATTACHMENTS> colorAttachments;
  164. for(U i = 0; i < m_colorAttachmentCount; ++i)
  165. {
  166. const FramebufferDescriptionAttachment& inAtt = m_colorAttachments[i];
  167. colorAttachments[i].m_surf = inAtt.m_surface;
  168. colorAttachments[i].m_loadOp = static_cast<U32>(inAtt.m_loadOperation);
  169. colorAttachments[i].m_storeOp = static_cast<U32>(inAtt.m_storeOperation);
  170. memcpy(&colorAttachments[i].m_clearColor[0], &inAtt.m_clearValue.m_coloru[0], sizeof(U32) * 4);
  171. }
  172. m_hash = computeHash(&colorAttachments[0], sizeof(ColorAttachment) * m_colorAttachmentCount);
  173. }
  174. // DS attachment
  175. if(!!m_depthStencilAttachment.m_aspect)
  176. {
  177. ANKI_BEGIN_PACKED_STRUCT
  178. struct DSAttachment
  179. {
  180. TextureSurfaceInfo m_surf;
  181. U32 m_loadOp;
  182. U32 m_storeOp;
  183. U32 m_stencilLoadOp;
  184. U32 m_stencilStoreOp;
  185. U32 m_aspect;
  186. F32 m_depthClear;
  187. I32 m_stencilClear;
  188. } outAtt;
  189. ANKI_END_PACKED_STRUCT
  190. const FramebufferDescriptionAttachment& inAtt = m_depthStencilAttachment;
  191. const Bool hasDepth = !!(inAtt.m_aspect & DepthStencilAspectBit::DEPTH);
  192. const Bool hasStencil = !!(inAtt.m_aspect & DepthStencilAspectBit::STENCIL);
  193. outAtt.m_surf = inAtt.m_surface;
  194. outAtt.m_loadOp = (hasDepth) ? static_cast<U32>(inAtt.m_loadOperation) : 0;
  195. outAtt.m_storeOp = (hasDepth) ? static_cast<U32>(inAtt.m_storeOperation) : 0;
  196. outAtt.m_stencilLoadOp = (hasStencil) ? static_cast<U32>(inAtt.m_stencilLoadOperation) : 0;
  197. outAtt.m_stencilStoreOp = (hasStencil) ? static_cast<U32>(inAtt.m_stencilStoreOperation) : 0;
  198. outAtt.m_aspect = static_cast<U32>(inAtt.m_aspect);
  199. outAtt.m_depthClear = (hasDepth) ? inAtt.m_clearValue.m_depthStencil.m_depth : 0.0f;
  200. outAtt.m_stencilClear = (hasStencil) ? inAtt.m_clearValue.m_depthStencil.m_stencil : 0;
  201. m_hash = (m_hash != 0) ? appendHash(&outAtt, sizeof(outAtt), m_hash) : computeHash(&outAtt, sizeof(outAtt));
  202. }
  203. ANKI_ASSERT(m_hash != 0 && m_hash != 1);
  204. }
  205. RenderGraph::RenderGraph(GrManager* manager, CString name)
  206. : GrObject(manager, CLASS_TYPE, name)
  207. {
  208. ANKI_ASSERT(manager);
  209. }
  210. RenderGraph::~RenderGraph()
  211. {
  212. ANKI_ASSERT(m_ctx == nullptr);
  213. while(!m_renderTargetCache.isEmpty())
  214. {
  215. auto it = m_renderTargetCache.getBegin();
  216. RenderTargetCacheEntry& entry = *it;
  217. entry.m_textures.destroy(getAllocator());
  218. m_renderTargetCache.erase(getAllocator(), it);
  219. }
  220. m_fbCache.destroy(getAllocator());
  221. for(auto& it : m_importedRenderTargets)
  222. {
  223. it.m_surfOrVolLastUsages.destroy(getAllocator());
  224. }
  225. m_importedRenderTargets.destroy(getAllocator());
  226. }
  227. RenderGraph* RenderGraph::newInstance(GrManager* manager)
  228. {
  229. return manager->getAllocator().newInstance<RenderGraph>(manager, "N/A");
  230. }
  231. void RenderGraph::reset()
  232. {
  233. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_RESET);
  234. if(!m_ctx)
  235. {
  236. return;
  237. }
  238. if((m_version % PERIODIC_CLEANUP_EVERY) == 0)
  239. {
  240. // Do cleanup
  241. periodicCleanup();
  242. }
  243. // Extract the final usage of the imported RTs and clean all RTs
  244. for(RT& rt : m_ctx->m_rts)
  245. {
  246. if(rt.m_imported)
  247. {
  248. const U32 surfOrVolumeCount = getTextureSurfOrVolCount(rt.m_texture);
  249. // Create a new hash because our hash map dislikes concurent keys.
  250. const U64 uuid = rt.m_texture->getUuid();
  251. const U64 hash = computeHash(&uuid, sizeof(uuid));
  252. auto it = m_importedRenderTargets.find(hash);
  253. if(it != m_importedRenderTargets.getEnd())
  254. {
  255. // Found
  256. ANKI_ASSERT(it->m_surfOrVolLastUsages.getSize() == surfOrVolumeCount);
  257. ANKI_ASSERT(rt.m_surfOrVolUsages.getSize() == surfOrVolumeCount);
  258. }
  259. else
  260. {
  261. // Not found, create
  262. it = m_importedRenderTargets.emplace(getAllocator(), hash);
  263. it->m_surfOrVolLastUsages.create(getAllocator(), surfOrVolumeCount);
  264. }
  265. // Update the usage
  266. for(U32 surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
  267. {
  268. it->m_surfOrVolLastUsages[surfOrVolIdx] = rt.m_surfOrVolUsages[surfOrVolIdx];
  269. }
  270. }
  271. rt.m_texture.reset(nullptr);
  272. }
  273. for(Buffer& buff : m_ctx->m_buffers)
  274. {
  275. buff.m_buffer.reset(nullptr);
  276. }
  277. for(AS& as : m_ctx->m_as)
  278. {
  279. as.m_as.reset(nullptr);
  280. }
  281. for(auto& it : m_renderTargetCache)
  282. {
  283. it.m_texturesInUse = 0;
  284. }
  285. for(Pass& p : m_ctx->m_passes)
  286. {
  287. p.fb().reset(nullptr);
  288. p.m_secondLevelCmdbs.destroy(m_ctx->m_alloc);
  289. p.m_callback.destroy(m_ctx->m_alloc);
  290. }
  291. m_ctx->m_graphicsCmdbs.destroy(m_ctx->m_alloc);
  292. m_ctx->m_alloc = StackAllocator<U8>();
  293. m_ctx = nullptr;
  294. ++m_version;
  295. }
  296. TexturePtr RenderGraph::getOrCreateRenderTarget(const TextureInitInfo& initInf, U64 hash)
  297. {
  298. ANKI_ASSERT(hash);
  299. auto alloc = getManager().getAllocator();
  300. // Find a cache entry
  301. RenderTargetCacheEntry* entry = nullptr;
  302. auto it = m_renderTargetCache.find(hash);
  303. if(ANKI_UNLIKELY(it == m_renderTargetCache.getEnd()))
  304. {
  305. // Didn't found the entry, create a new one
  306. auto it2 = m_renderTargetCache.emplace(getAllocator(), hash);
  307. entry = &(*it2);
  308. }
  309. else
  310. {
  311. entry = &(*it);
  312. }
  313. ANKI_ASSERT(entry);
  314. // Create or pop one tex from the cache
  315. TexturePtr tex;
  316. const Bool createNewTex = entry->m_textures.getSize() == entry->m_texturesInUse;
  317. if(!createNewTex)
  318. {
  319. // Pop
  320. tex = entry->m_textures[entry->m_texturesInUse++];
  321. }
  322. else
  323. {
  324. // Create it
  325. tex = getManager().newTexture(initInf);
  326. ANKI_ASSERT(entry->m_texturesInUse == entry->m_textures.getSize());
  327. entry->m_textures.resize(alloc, entry->m_textures.getSize() + 1);
  328. entry->m_textures[entry->m_textures.getSize() - 1] = tex;
  329. ++entry->m_texturesInUse;
  330. }
  331. return tex;
  332. }
  333. FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription& fbDescr,
  334. const RenderTargetHandle* rtHandles, CString name,
  335. Bool& drawsToPresentable)
  336. {
  337. ANKI_ASSERT(rtHandles);
  338. U64 hash = fbDescr.m_hash;
  339. ANKI_ASSERT(hash > 0);
  340. drawsToPresentable = false;
  341. // Create a hash that includes the render targets
  342. Array<U64, MAX_COLOR_ATTACHMENTS + 1> uuids;
  343. U count = 0;
  344. for(U i = 0; i < fbDescr.m_colorAttachmentCount; ++i)
  345. {
  346. uuids[count++] = m_ctx->m_rts[rtHandles[i].m_idx].m_texture->getUuid();
  347. if(!!(m_ctx->m_rts[rtHandles[i].m_idx].m_texture->getTextureUsage() & TextureUsageBit::PRESENT))
  348. {
  349. drawsToPresentable = true;
  350. }
  351. }
  352. if(!!fbDescr.m_depthStencilAttachment.m_aspect)
  353. {
  354. uuids[count++] = m_ctx->m_rts[rtHandles[MAX_COLOR_ATTACHMENTS].m_idx].m_texture->getUuid();
  355. }
  356. hash = appendHash(&uuids[0], sizeof(U64) * count, hash);
  357. FramebufferPtr fb;
  358. auto it = m_fbCache.find(hash);
  359. if(it != m_fbCache.getEnd())
  360. {
  361. fb = *it;
  362. }
  363. else
  364. {
  365. // Create a complete fb init info
  366. FramebufferInitInfo fbInit;
  367. fbInit.m_colorAttachmentCount = fbDescr.m_colorAttachmentCount;
  368. for(U i = 0; i < fbInit.m_colorAttachmentCount; ++i)
  369. {
  370. FramebufferAttachmentInfo& outAtt = fbInit.m_colorAttachments[i];
  371. const FramebufferDescriptionAttachment& inAtt = fbDescr.m_colorAttachments[i];
  372. outAtt.m_clearValue = inAtt.m_clearValue;
  373. outAtt.m_loadOperation = inAtt.m_loadOperation;
  374. outAtt.m_storeOperation = inAtt.m_storeOperation;
  375. // Create texture view
  376. TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[i].m_idx].m_texture,
  377. TextureSubresourceInfo(inAtt.m_surface), "RenderGraph");
  378. TextureViewPtr view = getManager().newTextureView(viewInit);
  379. outAtt.m_textureView = view;
  380. }
  381. if(!!fbDescr.m_depthStencilAttachment.m_aspect)
  382. {
  383. FramebufferAttachmentInfo& outAtt = fbInit.m_depthStencilAttachment;
  384. const FramebufferDescriptionAttachment& inAtt = fbDescr.m_depthStencilAttachment;
  385. outAtt.m_clearValue = inAtt.m_clearValue;
  386. outAtt.m_loadOperation = inAtt.m_loadOperation;
  387. outAtt.m_storeOperation = inAtt.m_storeOperation;
  388. outAtt.m_stencilLoadOperation = inAtt.m_stencilLoadOperation;
  389. outAtt.m_stencilStoreOperation = inAtt.m_stencilStoreOperation;
  390. // Create texture view
  391. TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[MAX_COLOR_ATTACHMENTS].m_idx].m_texture,
  392. TextureSubresourceInfo(inAtt.m_surface, inAtt.m_aspect), "RenderGraph");
  393. TextureViewPtr view = getManager().newTextureView(viewInit);
  394. outAtt.m_textureView = view;
  395. }
  396. // Set FB name
  397. Array<char, MAX_GR_OBJECT_NAME_LENGTH + 1> cutName;
  398. const U cutNameLen = min<U>(name.getLength(), MAX_GR_OBJECT_NAME_LENGTH);
  399. memcpy(&cutName[0], &name[0], cutNameLen);
  400. cutName[cutNameLen] = '\0';
  401. fbInit.setName(&cutName[0]);
  402. // Create
  403. fb = getManager().newFramebuffer(fbInit);
  404. m_fbCache.emplace(getAllocator(), hash, fb);
  405. }
  406. return fb;
  407. }
  408. Bool RenderGraph::overlappingTextureSubresource(const TextureSubresourceInfo& suba, const TextureSubresourceInfo& subb)
  409. {
  410. #define ANKI_OVERLAPPING(first, count) \
  411. ((suba.first < subb.first + subb.count) && (subb.first < suba.first + suba.count))
  412. const Bool overlappingFaces = ANKI_OVERLAPPING(m_firstFace, m_faceCount);
  413. const Bool overlappingMips = ANKI_OVERLAPPING(m_firstMipmap, m_mipmapCount);
  414. const Bool overlappingLayers = ANKI_OVERLAPPING(m_firstLayer, m_layerCount);
  415. #undef ANKI_OVERLAPPING
  416. return overlappingFaces && overlappingLayers && overlappingMips;
  417. }
  418. Bool RenderGraph::passADependsOnB(const RenderPassDescriptionBase& a, const RenderPassDescriptionBase& b)
  419. {
  420. // Render targets
  421. {
  422. // Compute the 3 types of dependencies
  423. const BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64> aReadBWrite = a.m_readRtMask & b.m_writeRtMask;
  424. const BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64> aWriteBRead = a.m_writeRtMask & b.m_readRtMask;
  425. const BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64> aWriteBWrite = a.m_writeRtMask & b.m_writeRtMask;
  426. const BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
  427. if(fullDep.getAny())
  428. {
  429. // There might be an overlap
  430. for(const RenderPassDependency& aDep : a.m_rtDeps)
  431. {
  432. if(!fullDep.get(aDep.m_texture.m_handle.m_idx))
  433. {
  434. continue;
  435. }
  436. for(const RenderPassDependency& bDep : b.m_rtDeps)
  437. {
  438. if(aDep.m_texture.m_handle != bDep.m_texture.m_handle)
  439. {
  440. continue;
  441. }
  442. if(!((aDep.m_texture.m_usage | bDep.m_texture.m_usage) & TextureUsageBit::ALL_WRITE))
  443. {
  444. // Don't care about read to read deps
  445. continue;
  446. }
  447. if(overlappingTextureSubresource(aDep.m_texture.m_subresource, bDep.m_texture.m_subresource))
  448. {
  449. return true;
  450. }
  451. }
  452. }
  453. }
  454. }
  455. // Buffers
  456. if(a.m_readBuffMask || a.m_writeBuffMask)
  457. {
  458. const BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> aReadBWrite = a.m_readBuffMask & b.m_writeBuffMask;
  459. const BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> aWriteBRead = a.m_writeBuffMask & b.m_readBuffMask;
  460. const BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> aWriteBWrite = a.m_writeBuffMask & b.m_writeBuffMask;
  461. const BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
  462. if(fullDep.getAny())
  463. {
  464. // There might be an overlap
  465. for(const RenderPassDependency& aDep : a.m_buffDeps)
  466. {
  467. if(!fullDep.get(aDep.m_buffer.m_handle.m_idx))
  468. {
  469. continue;
  470. }
  471. for(const RenderPassDependency& bDep : b.m_buffDeps)
  472. {
  473. if(aDep.m_buffer.m_handle != bDep.m_buffer.m_handle)
  474. {
  475. continue;
  476. }
  477. if(!((aDep.m_buffer.m_usage | bDep.m_buffer.m_usage) & BufferUsageBit::ALL_WRITE))
  478. {
  479. // Don't care about read to read deps
  480. continue;
  481. }
  482. // TODO: Take into account the ranges
  483. return true;
  484. }
  485. }
  486. }
  487. }
  488. // AS
  489. if(a.m_readAsMask || a.m_writeAsMask)
  490. {
  491. const BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> aReadBWrite = a.m_readAsMask & b.m_writeAsMask;
  492. const BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> aWriteBRead = a.m_writeAsMask & b.m_readAsMask;
  493. const BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> aWriteBWrite = a.m_writeAsMask & b.m_writeAsMask;
  494. const BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
  495. if(fullDep)
  496. {
  497. for(const RenderPassDependency& aDep : a.m_asDeps)
  498. {
  499. if(!fullDep.get(aDep.m_as.m_handle.m_idx))
  500. {
  501. continue;
  502. }
  503. for(const RenderPassDependency& bDep : b.m_asDeps)
  504. {
  505. if(aDep.m_as.m_handle != bDep.m_as.m_handle)
  506. {
  507. continue;
  508. }
  509. if(!((aDep.m_as.m_usage | bDep.m_as.m_usage) & AccelerationStructureUsageBit::ALL_WRITE))
  510. {
  511. // Don't care about read to read deps
  512. continue;
  513. }
  514. return true;
  515. }
  516. }
  517. }
  518. }
  519. return false;
  520. }
  521. Bool RenderGraph::passHasUnmetDependencies(const BakeContext& ctx, U32 passIdx)
  522. {
  523. Bool depends = false;
  524. if(ctx.m_batches.getSize() > 0)
  525. {
  526. // Check if the deps of passIdx are all in a batch
  527. for(const U32 depPassIdx : ctx.m_passes[passIdx].m_dependsOn)
  528. {
  529. if(ctx.m_passIsInBatch.get(depPassIdx) == false)
  530. {
  531. // Dependency pass is not in a batch
  532. depends = true;
  533. break;
  534. }
  535. }
  536. }
  537. else
  538. {
  539. // First batch, check if passIdx depends on any pass
  540. depends = ctx.m_passes[passIdx].m_dependsOn.getSize() != 0;
  541. }
  542. return depends;
  543. }
  544. RenderGraph::BakeContext* RenderGraph::newContext(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  545. {
  546. // Allocate
  547. BakeContext* ctx = alloc.newInstance<BakeContext>(alloc);
  548. // Init the resources
  549. ctx->m_rts.create(alloc, descr.m_renderTargets.getSize());
  550. for(U32 rtIdx = 0; rtIdx < ctx->m_rts.getSize(); ++rtIdx)
  551. {
  552. RT& outRt = ctx->m_rts[rtIdx];
  553. const RenderGraphDescription::RT& inRt = descr.m_renderTargets[rtIdx];
  554. const Bool imported = inRt.m_importedTex.isCreated();
  555. if(imported)
  556. {
  557. // It's imported
  558. outRt.m_texture = inRt.m_importedTex;
  559. }
  560. else
  561. {
  562. // Need to create new
  563. // Create a new TextureInitInfo with the derived usage
  564. TextureInitInfo initInf = inRt.m_initInfo;
  565. initInf.m_usage = inRt.m_usageDerivedByDeps;
  566. ANKI_ASSERT(initInf.m_usage != TextureUsageBit::NONE && "Probably not referenced by any pass");
  567. // Create the new hash
  568. const U64 hash = appendHash(&initInf.m_usage, sizeof(initInf.m_usage), inRt.m_hash);
  569. // Get or create the texture
  570. outRt.m_texture = getOrCreateRenderTarget(initInf, hash);
  571. }
  572. // Init the usage
  573. const U32 surfOrVolumeCount = getTextureSurfOrVolCount(outRt.m_texture);
  574. outRt.m_surfOrVolUsages.create(alloc, surfOrVolumeCount, TextureUsageBit::NONE);
  575. if(imported && inRt.m_importedAndUndefinedUsage)
  576. {
  577. // Get the usage from previous frames
  578. // Create a new hash because our hash map dislikes concurent keys.
  579. const U64 uuid = outRt.m_texture->getUuid();
  580. const U64 hash = computeHash(&uuid, sizeof(uuid));
  581. auto it = m_importedRenderTargets.find(hash);
  582. ANKI_ASSERT(it != m_importedRenderTargets.getEnd() && "Can't find the imported RT");
  583. ANKI_ASSERT(it->m_surfOrVolLastUsages.getSize() == surfOrVolumeCount);
  584. for(U32 surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
  585. {
  586. outRt.m_surfOrVolUsages[surfOrVolIdx] = it->m_surfOrVolLastUsages[surfOrVolIdx];
  587. }
  588. }
  589. else if(imported)
  590. {
  591. // Set the usage that was given by the user
  592. for(U32 surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
  593. {
  594. outRt.m_surfOrVolUsages[surfOrVolIdx] = inRt.m_importedLastKnownUsage;
  595. }
  596. }
  597. outRt.m_lastBatchThatTransitionedIt.create(alloc, surfOrVolumeCount, MAX_U16);
  598. outRt.m_imported = imported;
  599. }
  600. // Buffers
  601. ctx->m_buffers.create(alloc, descr.m_buffers.getSize());
  602. for(U32 buffIdx = 0; buffIdx < ctx->m_buffers.getSize(); ++buffIdx)
  603. {
  604. ctx->m_buffers[buffIdx].m_usage = descr.m_buffers[buffIdx].m_usage;
  605. ANKI_ASSERT(descr.m_buffers[buffIdx].m_importedBuff.isCreated());
  606. ctx->m_buffers[buffIdx].m_buffer = descr.m_buffers[buffIdx].m_importedBuff;
  607. ctx->m_buffers[buffIdx].m_offset = descr.m_buffers[buffIdx].m_offset;
  608. ctx->m_buffers[buffIdx].m_range = descr.m_buffers[buffIdx].m_range;
  609. }
  610. // AS
  611. ctx->m_as.create(alloc, descr.m_as.getSize());
  612. for(U32 i = 0; i < descr.m_as.getSize(); ++i)
  613. {
  614. ctx->m_as[i].m_usage = descr.m_as[i].m_usage;
  615. ctx->m_as[i].m_as = descr.m_as[i].m_importedAs;
  616. ANKI_ASSERT(ctx->m_as[i].m_as.isCreated());
  617. }
  618. ctx->m_gatherStatistics = descr.m_gatherStatistics;
  619. return ctx;
  620. }
  621. void RenderGraph::initRenderPassesAndSetDeps(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  622. {
  623. BakeContext& ctx = *m_ctx;
  624. const U32 passCount = descr.m_passes.getSize();
  625. ANKI_ASSERT(passCount > 0);
  626. ctx.m_passes.create(alloc, passCount);
  627. for(U32 passIdx = 0; passIdx < passCount; ++passIdx)
  628. {
  629. const RenderPassDescriptionBase& inPass = *descr.m_passes[passIdx];
  630. Pass& outPass = ctx.m_passes[passIdx];
  631. outPass.m_callback.copy(inPass.m_callback, alloc);
  632. // Create consumer info
  633. outPass.m_consumedTextures.resize(alloc, inPass.m_rtDeps.getSize());
  634. for(U32 depIdx = 0; depIdx < inPass.m_rtDeps.getSize(); ++depIdx)
  635. {
  636. const RenderPassDependency& inDep = inPass.m_rtDeps[depIdx];
  637. ANKI_ASSERT(inDep.m_type == RenderPassDependency::Type::TEXTURE);
  638. RenderPassDependency::TextureInfo& inf = outPass.m_consumedTextures[depIdx];
  639. ANKI_ASSERT(sizeof(inf) == sizeof(inDep.m_texture));
  640. memcpy(&inf, &inDep.m_texture, sizeof(inf));
  641. }
  642. // Create command buffers and framebuffer
  643. if(inPass.m_type == RenderPassDescriptionBase::Type::GRAPHICS)
  644. {
  645. const GraphicsRenderPassDescription& graphicsPass =
  646. static_cast<const GraphicsRenderPassDescription&>(inPass);
  647. if(graphicsPass.hasFramebuffer())
  648. {
  649. Bool drawsToPresentable;
  650. outPass.fb() = getOrCreateFramebuffer(graphicsPass.m_fbDescr, &graphicsPass.m_rtHandles[0],
  651. inPass.m_name.cstr(), drawsToPresentable);
  652. outPass.m_fbRenderArea = graphicsPass.m_fbRenderArea;
  653. outPass.m_drawsToPresentable = drawsToPresentable;
  654. }
  655. else
  656. {
  657. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  658. }
  659. }
  660. else
  661. {
  662. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  663. }
  664. // Set dependencies by checking all previous subpasses.
  665. U32 prevPassIdx = passIdx;
  666. while(prevPassIdx--)
  667. {
  668. const RenderPassDescriptionBase& prevPass = *descr.m_passes[prevPassIdx];
  669. if(passADependsOnB(inPass, prevPass))
  670. {
  671. outPass.m_dependsOn.emplaceBack(alloc, prevPassIdx);
  672. }
  673. }
  674. }
  675. }
  676. void RenderGraph::initBatches()
  677. {
  678. ANKI_ASSERT(m_ctx);
  679. U passesAssignedToBatchCount = 0;
  680. const U passCount = m_ctx->m_passes.getSize();
  681. ANKI_ASSERT(passCount > 0);
  682. Bool setTimestamp = m_ctx->m_gatherStatistics;
  683. while(passesAssignedToBatchCount < passCount)
  684. {
  685. m_ctx->m_batches.emplaceBack(m_ctx->m_alloc);
  686. Batch& batch = m_ctx->m_batches.getBack();
  687. Bool drawsToPresentable = false;
  688. for(U32 i = 0; i < passCount; ++i)
  689. {
  690. if(!m_ctx->m_passIsInBatch.get(i) && !passHasUnmetDependencies(*m_ctx, i))
  691. {
  692. // Add to the batch
  693. ++passesAssignedToBatchCount;
  694. batch.m_passIndices.emplaceBack(m_ctx->m_alloc, i);
  695. // Will batch draw to the swapchain?
  696. drawsToPresentable = drawsToPresentable || m_ctx->m_passes[i].m_drawsToPresentable;
  697. }
  698. }
  699. // Get or create cmdb for the batch.
  700. // Create a new cmdb if the batch is writing to swapchain. This will help Vulkan to have a dependency of the
  701. // swap chain image acquire to the 2nd command buffer instead of adding it to a single big cmdb.
  702. if(m_ctx->m_graphicsCmdbs.isEmpty() || drawsToPresentable)
  703. {
  704. CommandBufferInitInfo cmdbInit;
  705. cmdbInit.m_flags = CommandBufferFlag::GENERAL_WORK;
  706. CommandBufferPtr cmdb = getManager().newCommandBuffer(cmdbInit);
  707. m_ctx->m_graphicsCmdbs.emplaceBack(m_ctx->m_alloc, cmdb);
  708. batch.m_cmdb = cmdb.get();
  709. // Maybe write a timestamp
  710. if(ANKI_UNLIKELY(setTimestamp))
  711. {
  712. setTimestamp = false;
  713. TimestampQueryPtr query = getManager().newTimestampQuery();
  714. cmdb->resetTimestampQuery(query);
  715. cmdb->writeTimestamp(query);
  716. m_statistics.m_nextTimestamp = (m_statistics.m_nextTimestamp + 1) % MAX_TIMESTAMPS_BUFFERED;
  717. m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2] = query;
  718. }
  719. }
  720. else
  721. {
  722. batch.m_cmdb = m_ctx->m_graphicsCmdbs.getBack().get();
  723. }
  724. // Mark batch's passes done
  725. for(U32 passIdx : m_ctx->m_batches.getBack().m_passIndices)
  726. {
  727. m_ctx->m_passIsInBatch.set(passIdx);
  728. m_ctx->m_passes[passIdx].m_batchIdx = m_ctx->m_batches.getSize() - 1;
  729. }
  730. }
  731. }
  732. void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  733. {
  734. BakeContext& ctx = *m_ctx;
  735. const U32 passCount = descr.m_passes.getSize();
  736. ANKI_ASSERT(passCount > 0);
  737. for(U32 passIdx = 0; passIdx < passCount; ++passIdx)
  738. {
  739. const RenderPassDescriptionBase& inPass = *descr.m_passes[passIdx];
  740. Pass& outPass = ctx.m_passes[passIdx];
  741. // Create command buffers and framebuffer
  742. if(inPass.m_type == RenderPassDescriptionBase::Type::GRAPHICS)
  743. {
  744. const GraphicsRenderPassDescription& graphicsPass =
  745. static_cast<const GraphicsRenderPassDescription&>(inPass);
  746. if(graphicsPass.hasFramebuffer())
  747. {
  748. // Init the usage bits
  749. TextureUsageBit usage;
  750. for(U i = 0; i < graphicsPass.m_fbDescr.m_colorAttachmentCount; ++i)
  751. {
  752. getCrntUsage(graphicsPass.m_rtHandles[i], outPass.m_batchIdx,
  753. TextureSubresourceInfo(graphicsPass.m_fbDescr.m_colorAttachments[i].m_surface), usage);
  754. outPass.m_colorUsages[i] = usage;
  755. }
  756. if(!!graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect)
  757. {
  758. TextureSubresourceInfo subresource =
  759. TextureSubresourceInfo(graphicsPass.m_fbDescr.m_depthStencilAttachment.m_surface,
  760. graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect);
  761. getCrntUsage(graphicsPass.m_rtHandles[MAX_COLOR_ATTACHMENTS], outPass.m_batchIdx, subresource,
  762. usage);
  763. outPass.m_dsUsage = usage;
  764. }
  765. // Do some pre-work for the second level command buffers
  766. if(inPass.m_secondLevelCmdbsCount)
  767. {
  768. outPass.m_secondLevelCmdbs.create(alloc, inPass.m_secondLevelCmdbsCount);
  769. CommandBufferInitInfo& cmdbInit = outPass.m_secondLevelCmdbInitInfo;
  770. cmdbInit.m_flags = CommandBufferFlag::GENERAL_WORK | CommandBufferFlag::SECOND_LEVEL;
  771. ANKI_ASSERT(cmdbInit.m_framebuffer.isCreated());
  772. cmdbInit.m_colorAttachmentUsages = outPass.m_colorUsages;
  773. cmdbInit.m_depthStencilAttachmentUsage = outPass.m_dsUsage;
  774. }
  775. }
  776. else
  777. {
  778. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  779. }
  780. }
  781. else
  782. {
  783. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  784. }
  785. }
  786. }
  787. template<typename TFunc>
  788. void RenderGraph::iterateSurfsOrVolumes(const TexturePtr& tex, const TextureSubresourceInfo& subresource, TFunc func)
  789. {
  790. for(U32 mip = subresource.m_firstMipmap; mip < subresource.m_firstMipmap + subresource.m_mipmapCount; ++mip)
  791. {
  792. for(U32 layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount; ++layer)
  793. {
  794. for(U32 face = subresource.m_firstFace; face < U32(subresource.m_firstFace + subresource.m_faceCount);
  795. ++face)
  796. {
  797. // Compute surf or vol idx
  798. const U32 faceCount = textureTypeIsCube(tex->getTextureType()) ? 6 : 1;
  799. const U32 idx = (faceCount * tex->getLayerCount()) * mip + faceCount * layer + face;
  800. const TextureSurfaceInfo surf(mip, 0, face, layer);
  801. if(!func(idx, surf))
  802. {
  803. return;
  804. }
  805. }
  806. }
  807. }
  808. }
  809. void RenderGraph::setTextureBarrier(Batch& batch, const RenderPassDependency& dep)
  810. {
  811. ANKI_ASSERT(dep.m_type == RenderPassDependency::Type::TEXTURE);
  812. BakeContext& ctx = *m_ctx;
  813. const U32 batchIdx = U32(&batch - &ctx.m_batches[0]);
  814. const U32 rtIdx = dep.m_texture.m_handle.m_idx;
  815. const TextureUsageBit depUsage = dep.m_texture.m_usage;
  816. RT& rt = ctx.m_rts[rtIdx];
  817. iterateSurfsOrVolumes(
  818. rt.m_texture, dep.m_texture.m_subresource, [&](U32 surfOrVolIdx, const TextureSurfaceInfo& surf) {
  819. TextureUsageBit& crntUsage = rt.m_surfOrVolUsages[surfOrVolIdx];
  820. if(crntUsage != depUsage)
  821. {
  822. // Check if we can merge barriers
  823. if(rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] == batchIdx)
  824. {
  825. // Will merge the barriers
  826. crntUsage |= depUsage;
  827. Bool found = false;
  828. for(TextureBarrier& b : batch.m_textureBarriersBefore)
  829. {
  830. if(b.m_idx == rtIdx && b.m_surface == surf)
  831. {
  832. b.m_usageAfter |= depUsage;
  833. found = true;
  834. break;
  835. }
  836. }
  837. (void)found;
  838. ANKI_ASSERT(found);
  839. }
  840. else
  841. {
  842. // Create a new barrier for this surface
  843. batch.m_textureBarriersBefore.emplaceBack(ctx.m_alloc, rtIdx, crntUsage, depUsage, surf);
  844. crntUsage = depUsage;
  845. rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] = U16(batchIdx);
  846. }
  847. }
  848. return true;
  849. });
  850. }
  851. void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr)
  852. {
  853. BakeContext& ctx = *m_ctx;
  854. const StackAllocator<U8>& alloc = ctx.m_alloc;
  855. // For all batches
  856. for(Batch& batch : ctx.m_batches)
  857. {
  858. BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> buffHasBarrierMask(false);
  859. BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> asHasBarrierMask(false);
  860. // For all passes of that batch
  861. for(U32 passIdx : batch.m_passIndices)
  862. {
  863. const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
  864. // Do textures
  865. for(const RenderPassDependency& dep : pass.m_rtDeps)
  866. {
  867. setTextureBarrier(batch, dep);
  868. }
  869. // Do buffers
  870. for(const RenderPassDependency& dep : pass.m_buffDeps)
  871. {
  872. const U32 buffIdx = dep.m_buffer.m_handle.m_idx;
  873. const BufferUsageBit depUsage = dep.m_buffer.m_usage;
  874. BufferUsageBit& crntUsage = ctx.m_buffers[buffIdx].m_usage;
  875. if(depUsage == crntUsage)
  876. {
  877. continue;
  878. }
  879. const Bool buffHasBarrier = buffHasBarrierMask.get(buffIdx);
  880. if(!buffHasBarrier)
  881. {
  882. // Buff hasn't had a barrier in this batch, add a new barrier
  883. batch.m_bufferBarriersBefore.emplaceBack(alloc, buffIdx, crntUsage, depUsage);
  884. crntUsage = depUsage;
  885. buffHasBarrierMask.set(buffIdx);
  886. }
  887. else
  888. {
  889. // Buff already in a barrier, merge the 2 barriers
  890. BufferBarrier* barrierToMergeTo = nullptr;
  891. for(BufferBarrier& b : batch.m_bufferBarriersBefore)
  892. {
  893. if(b.m_idx == buffIdx)
  894. {
  895. barrierToMergeTo = &b;
  896. break;
  897. }
  898. }
  899. ANKI_ASSERT(barrierToMergeTo);
  900. ANKI_ASSERT(!!barrierToMergeTo->m_usageAfter);
  901. barrierToMergeTo->m_usageAfter |= depUsage;
  902. crntUsage = barrierToMergeTo->m_usageAfter;
  903. }
  904. }
  905. // Do AS
  906. for(const RenderPassDependency& dep : pass.m_asDeps)
  907. {
  908. const U32 asIdx = dep.m_as.m_handle.m_idx;
  909. const AccelerationStructureUsageBit depUsage = dep.m_as.m_usage;
  910. AccelerationStructureUsageBit& crntUsage = ctx.m_as[asIdx].m_usage;
  911. if(depUsage == crntUsage)
  912. {
  913. continue;
  914. }
  915. const Bool asHasBarrierInThisBatch = asHasBarrierMask.get(asIdx);
  916. if(!asHasBarrierInThisBatch)
  917. {
  918. // AS doesn't have a barrier in this batch, create a new one
  919. batch.m_asBarriersBefore.emplaceBack(alloc, asIdx, crntUsage, depUsage);
  920. crntUsage = depUsage;
  921. asHasBarrierMask.set(asIdx);
  922. }
  923. else
  924. {
  925. // AS already has a barrier, merge the 2 barriers
  926. ASBarrier* barrierToMergeTo = nullptr;
  927. for(ASBarrier& other : batch.m_asBarriersBefore)
  928. {
  929. if(other.m_idx == asIdx)
  930. {
  931. barrierToMergeTo = &other;
  932. break;
  933. }
  934. }
  935. ANKI_ASSERT(barrierToMergeTo);
  936. ANKI_ASSERT(!!barrierToMergeTo->m_usageAfter);
  937. barrierToMergeTo->m_usageAfter |= depUsage;
  938. crntUsage = barrierToMergeTo->m_usageAfter;
  939. }
  940. }
  941. } // For all passes
  942. #if ANKI_DBG_RENDER_GRAPH
  943. // Sort the barriers to ease the dumped graph
  944. std::sort(batch.m_textureBarriersBefore.getBegin(), batch.m_textureBarriersBefore.getEnd(),
  945. [&](const TextureBarrier& a, const TextureBarrier& b) {
  946. const U aidx = a.m_idx;
  947. const U bidx = b.m_idx;
  948. if(aidx == bidx)
  949. {
  950. if(a.m_surface.m_level != b.m_surface.m_level)
  951. {
  952. return a.m_surface.m_level < b.m_surface.m_level;
  953. }
  954. else if(a.m_surface.m_face != b.m_surface.m_face)
  955. {
  956. return a.m_surface.m_face < b.m_surface.m_face;
  957. }
  958. else if(a.m_surface.m_layer != b.m_surface.m_layer)
  959. {
  960. return a.m_surface.m_layer < b.m_surface.m_layer;
  961. }
  962. else
  963. {
  964. return false;
  965. }
  966. }
  967. else
  968. {
  969. return aidx < bidx;
  970. }
  971. });
  972. std::sort(batch.m_bufferBarriersBefore.getBegin(), batch.m_bufferBarriersBefore.getEnd(),
  973. [&](const BufferBarrier& a, const BufferBarrier& b) { return a.m_idx < b.m_idx; });
  974. std::sort(batch.m_asBarriersBefore.getBegin(), batch.m_asBarriersBefore.getEnd(),
  975. [&](const ASBarrier& a, const ASBarrier& b) { return a.m_idx < b.m_idx; });
  976. #endif
  977. } // For all batches
  978. }
  979. void RenderGraph::compileNewGraph(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  980. {
  981. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_COMPILE);
  982. // Init the context
  983. BakeContext& ctx = *newContext(descr, alloc);
  984. m_ctx = &ctx;
  985. // Init the passes and find the dependencies between passes
  986. initRenderPassesAndSetDeps(descr, alloc);
  987. // Walk the graph and create pass batches
  988. initBatches();
  989. // Now that we know the batches every pass belongs init the graphics passes
  990. initGraphicsPasses(descr, alloc);
  991. // Create barriers between batches
  992. setBatchBarriers(descr);
  993. #if ANKI_DBG_RENDER_GRAPH
  994. if(dumpDependencyDotFile(descr, ctx, "./"))
  995. {
  996. ANKI_LOGF("Won't recover on debug code");
  997. }
  998. #endif
  999. }
  1000. TexturePtr RenderGraph::getTexture(RenderTargetHandle handle) const
  1001. {
  1002. ANKI_ASSERT(m_ctx->m_rts[handle.m_idx].m_texture.isCreated());
  1003. return m_ctx->m_rts[handle.m_idx].m_texture;
  1004. }
  1005. BufferPtr RenderGraph::getBuffer(BufferHandle handle) const
  1006. {
  1007. ANKI_ASSERT(m_ctx->m_buffers[handle.m_idx].m_buffer.isCreated());
  1008. return m_ctx->m_buffers[handle.m_idx].m_buffer;
  1009. }
  1010. AccelerationStructurePtr RenderGraph::getAs(AccelerationStructureHandle handle) const
  1011. {
  1012. ANKI_ASSERT(m_ctx->m_as[handle.m_idx].m_as.isCreated());
  1013. return m_ctx->m_as[handle.m_idx].m_as;
  1014. }
  1015. void RenderGraph::runSecondLevel(U32 threadIdx)
  1016. {
  1017. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_2ND_LEVEL);
  1018. ANKI_ASSERT(m_ctx);
  1019. RenderPassWorkContext ctx;
  1020. ctx.m_rgraph = this;
  1021. ctx.m_currentSecondLevelCommandBufferIndex = threadIdx;
  1022. for(Pass& p : m_ctx->m_passes)
  1023. {
  1024. const U32 size = p.m_secondLevelCmdbs.getSize();
  1025. if(threadIdx < size)
  1026. {
  1027. ANKI_ASSERT(!p.m_secondLevelCmdbs[threadIdx].isCreated());
  1028. p.m_secondLevelCmdbs[threadIdx] = getManager().newCommandBuffer(p.m_secondLevelCmdbInitInfo);
  1029. ctx.m_commandBuffer = p.m_secondLevelCmdbs[threadIdx];
  1030. ctx.m_secondLevelCommandBufferCount = size;
  1031. ctx.m_passIdx = U32(&p - &m_ctx->m_passes[0]);
  1032. ctx.m_batchIdx = p.m_batchIdx;
  1033. ANKI_ASSERT(ctx.m_commandBuffer.isCreated());
  1034. {
  1035. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_CALLBACK);
  1036. p.m_callback(ctx);
  1037. }
  1038. ctx.m_commandBuffer->flush();
  1039. }
  1040. }
  1041. }
  1042. void RenderGraph::run() const
  1043. {
  1044. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_RUN);
  1045. ANKI_ASSERT(m_ctx);
  1046. RenderPassWorkContext ctx;
  1047. ctx.m_rgraph = this;
  1048. ctx.m_currentSecondLevelCommandBufferIndex = 0;
  1049. ctx.m_secondLevelCommandBufferCount = 0;
  1050. for(const Batch& batch : m_ctx->m_batches)
  1051. {
  1052. ctx.m_commandBuffer.reset(batch.m_cmdb);
  1053. CommandBufferPtr& cmdb = ctx.m_commandBuffer;
  1054. // Set the barriers
  1055. for(const TextureBarrier& barrier : batch.m_textureBarriersBefore)
  1056. {
  1057. cmdb->setTextureSurfaceBarrier(m_ctx->m_rts[barrier.m_idx].m_texture, barrier.m_usageBefore,
  1058. barrier.m_usageAfter, barrier.m_surface);
  1059. }
  1060. for(const BufferBarrier& barrier : batch.m_bufferBarriersBefore)
  1061. {
  1062. const Buffer& b = m_ctx->m_buffers[barrier.m_idx];
  1063. cmdb->setBufferBarrier(b.m_buffer, barrier.m_usageBefore, barrier.m_usageAfter, b.m_offset, b.m_range);
  1064. }
  1065. for(const ASBarrier& barrier : batch.m_asBarriersBefore)
  1066. {
  1067. cmdb->setAccelerationStructureBarrier(m_ctx->m_as[barrier.m_idx].m_as, barrier.m_usageBefore,
  1068. barrier.m_usageAfter);
  1069. }
  1070. // Call the passes
  1071. for(U32 passIdx : batch.m_passIndices)
  1072. {
  1073. const Pass& pass = m_ctx->m_passes[passIdx];
  1074. if(pass.fb().isCreated())
  1075. {
  1076. cmdb->beginRenderPass(pass.fb(), pass.m_colorUsages, pass.m_dsUsage, pass.m_fbRenderArea[0],
  1077. pass.m_fbRenderArea[1], pass.m_fbRenderArea[2], pass.m_fbRenderArea[3]);
  1078. }
  1079. const U size = pass.m_secondLevelCmdbs.getSize();
  1080. if(size == 0)
  1081. {
  1082. ctx.m_passIdx = passIdx;
  1083. ctx.m_batchIdx = pass.m_batchIdx;
  1084. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_CALLBACK);
  1085. pass.m_callback(ctx);
  1086. }
  1087. else
  1088. {
  1089. for(const CommandBufferPtr& cmdb2nd : pass.m_secondLevelCmdbs)
  1090. {
  1091. cmdb->pushSecondLevelCommandBuffer(cmdb2nd);
  1092. }
  1093. }
  1094. if(pass.fb().isCreated())
  1095. {
  1096. cmdb->endRenderPass();
  1097. }
  1098. }
  1099. }
  1100. }
  1101. void RenderGraph::flush()
  1102. {
  1103. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_FLUSH);
  1104. for(U32 i = 0; i < m_ctx->m_graphicsCmdbs.getSize(); ++i)
  1105. {
  1106. if(ANKI_UNLIKELY(m_ctx->m_gatherStatistics && i == m_ctx->m_graphicsCmdbs.getSize() - 1))
  1107. {
  1108. // Write a timestamp before the last flush
  1109. TimestampQueryPtr query = getManager().newTimestampQuery();
  1110. m_ctx->m_graphicsCmdbs[i]->resetTimestampQuery(query);
  1111. m_ctx->m_graphicsCmdbs[i]->writeTimestamp(query);
  1112. m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2 + 1] = query;
  1113. m_statistics.m_cpuStartTimes[m_statistics.m_nextTimestamp] = HighRezTimer::getCurrentTime();
  1114. }
  1115. // Flush
  1116. m_ctx->m_graphicsCmdbs[i]->flush();
  1117. }
  1118. }
  1119. void RenderGraph::getCrntUsage(RenderTargetHandle handle, U32 batchIdx, const TextureSubresourceInfo& subresource,
  1120. TextureUsageBit& usage) const
  1121. {
  1122. usage = TextureUsageBit::NONE;
  1123. const Batch& batch = m_ctx->m_batches[batchIdx];
  1124. for(U32 passIdx : batch.m_passIndices)
  1125. {
  1126. for(const RenderPassDependency::TextureInfo& consumer : m_ctx->m_passes[passIdx].m_consumedTextures)
  1127. {
  1128. if(consumer.m_handle == handle && overlappingTextureSubresource(subresource, consumer.m_subresource))
  1129. {
  1130. usage |= consumer.m_usage;
  1131. break;
  1132. }
  1133. }
  1134. }
  1135. }
  1136. void RenderGraph::periodicCleanup()
  1137. {
  1138. U32 rtsCleanedCount = 0;
  1139. for(RenderTargetCacheEntry& entry : m_renderTargetCache)
  1140. {
  1141. if(entry.m_texturesInUse < entry.m_textures.getSize())
  1142. {
  1143. // Should cleanup
  1144. rtsCleanedCount += entry.m_textures.getSize() - entry.m_texturesInUse;
  1145. // New array
  1146. DynamicArray<TexturePtr> newArray;
  1147. if(entry.m_texturesInUse > 0)
  1148. {
  1149. newArray.create(getAllocator(), entry.m_texturesInUse);
  1150. }
  1151. // Populate the new array
  1152. for(U32 i = 0; i < newArray.getSize(); ++i)
  1153. {
  1154. newArray[i] = std::move(entry.m_textures[i]);
  1155. }
  1156. // Destroy the old array and the rest of the textures
  1157. entry.m_textures.destroy(getAllocator());
  1158. // Move new array
  1159. entry.m_textures = std::move(newArray);
  1160. }
  1161. }
  1162. if(rtsCleanedCount > 0)
  1163. {
  1164. ANKI_GR_LOGI("Cleaned %u render targets", rtsCleanedCount);
  1165. }
  1166. }
  1167. void RenderGraph::getStatistics(RenderGraphStatistics& statistics) const
  1168. {
  1169. const U32 oldFrame = (m_statistics.m_nextTimestamp + 1) % MAX_TIMESTAMPS_BUFFERED;
  1170. if(m_statistics.m_timestamps[oldFrame * 2] && m_statistics.m_timestamps[oldFrame * 2 + 1])
  1171. {
  1172. Second start, end;
  1173. TimestampQueryResult res = m_statistics.m_timestamps[oldFrame * 2]->getResult(start);
  1174. (void)res;
  1175. ANKI_ASSERT(res == TimestampQueryResult::AVAILABLE);
  1176. res = m_statistics.m_timestamps[oldFrame * 2 + 1]->getResult(end);
  1177. ANKI_ASSERT(res == TimestampQueryResult::AVAILABLE);
  1178. const Second diff = end - start;
  1179. statistics.m_gpuTime = diff;
  1180. statistics.m_cpuStartTime = m_statistics.m_cpuStartTimes[oldFrame];
  1181. }
  1182. else
  1183. {
  1184. statistics.m_gpuTime = -1.0;
  1185. statistics.m_cpuStartTime = -1.0;
  1186. }
  1187. }
  1188. #if ANKI_DBG_RENDER_GRAPH
  1189. StringAuto RenderGraph::textureUsageToStr(StackAllocator<U8>& alloc, TextureUsageBit usage)
  1190. {
  1191. StringListAuto slist(alloc);
  1192. # define ANKI_TEX_USAGE(u) \
  1193. if(!!(usage & TextureUsageBit::u)) \
  1194. { \
  1195. slist.pushBackSprintf("%s", #u); \
  1196. }
  1197. ANKI_TEX_USAGE(SAMPLED_GEOMETRY);
  1198. ANKI_TEX_USAGE(SAMPLED_FRAGMENT);
  1199. ANKI_TEX_USAGE(SAMPLED_COMPUTE);
  1200. ANKI_TEX_USAGE(SAMPLED_TRACE_RAYS);
  1201. ANKI_TEX_USAGE(IMAGE_GEOMETRY_READ);
  1202. ANKI_TEX_USAGE(IMAGE_GEOMETRY_WRITE);
  1203. ANKI_TEX_USAGE(IMAGE_FRAGMENT_READ);
  1204. ANKI_TEX_USAGE(IMAGE_FRAGMENT_WRITE);
  1205. ANKI_TEX_USAGE(IMAGE_COMPUTE_READ);
  1206. ANKI_TEX_USAGE(IMAGE_COMPUTE_WRITE);
  1207. ANKI_TEX_USAGE(IMAGE_TRACE_RAYS_READ);
  1208. ANKI_TEX_USAGE(IMAGE_TRACE_RAYS_WRITE);
  1209. ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_READ);
  1210. ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_WRITE);
  1211. ANKI_TEX_USAGE(TRANSFER_DESTINATION);
  1212. ANKI_TEX_USAGE(GENERATE_MIPMAPS);
  1213. ANKI_TEX_USAGE(PRESENT);
  1214. if(!usage)
  1215. {
  1216. slist.pushBackSprintf("NONE");
  1217. }
  1218. # undef ANKI_TEX_USAGE
  1219. ANKI_ASSERT(!slist.isEmpty());
  1220. StringAuto str(alloc);
  1221. slist.join(" | ", str);
  1222. return str;
  1223. }
  1224. StringAuto RenderGraph::bufferUsageToStr(StackAllocator<U8>& alloc, BufferUsageBit usage)
  1225. {
  1226. StringListAuto slist(alloc);
  1227. # define ANKI_BUFF_USAGE(u) \
  1228. if(!!(usage & BufferUsageBit::u)) \
  1229. { \
  1230. slist.pushBackSprintf("%s", #u); \
  1231. }
  1232. ANKI_BUFF_USAGE(UNIFORM_GEOMETRY);
  1233. ANKI_BUFF_USAGE(UNIFORM_FRAGMENT);
  1234. ANKI_BUFF_USAGE(UNIFORM_COMPUTE);
  1235. ANKI_BUFF_USAGE(UNIFORM_TRACE_RAYS);
  1236. ANKI_BUFF_USAGE(STORAGE_GEOMETRY_READ);
  1237. ANKI_BUFF_USAGE(STORAGE_GEOMETRY_WRITE);
  1238. ANKI_BUFF_USAGE(STORAGE_FRAGMENT_READ);
  1239. ANKI_BUFF_USAGE(STORAGE_FRAGMENT_WRITE);
  1240. ANKI_BUFF_USAGE(STORAGE_COMPUTE_READ);
  1241. ANKI_BUFF_USAGE(STORAGE_COMPUTE_WRITE);
  1242. ANKI_BUFF_USAGE(STORAGE_TRACE_RAYS_READ);
  1243. ANKI_BUFF_USAGE(STORAGE_TRACE_RAYS_WRITE);
  1244. ANKI_BUFF_USAGE(TEXTURE_GEOMETRY_READ);
  1245. ANKI_BUFF_USAGE(TEXTURE_GEOMETRY_WRITE);
  1246. ANKI_BUFF_USAGE(TEXTURE_FRAGMENT_READ);
  1247. ANKI_BUFF_USAGE(TEXTURE_FRAGMENT_WRITE);
  1248. ANKI_BUFF_USAGE(TEXTURE_COMPUTE_READ);
  1249. ANKI_BUFF_USAGE(TEXTURE_COMPUTE_WRITE);
  1250. ANKI_BUFF_USAGE(TEXTURE_TRACE_RAYS_READ);
  1251. ANKI_BUFF_USAGE(TEXTURE_TRACE_RAYS_WRITE);
  1252. ANKI_BUFF_USAGE(INDEX);
  1253. ANKI_BUFF_USAGE(VERTEX);
  1254. ANKI_BUFF_USAGE(INDIRECT_COMPUTE);
  1255. ANKI_BUFF_USAGE(INDIRECT_DRAW);
  1256. ANKI_BUFF_USAGE(INDIRECT_TRACE_RAYS);
  1257. ANKI_BUFF_USAGE(TRANSFER_SOURCE);
  1258. ANKI_BUFF_USAGE(TRANSFER_DESTINATION);
  1259. ANKI_BUFF_USAGE(ACCELERATION_STRUCTURE_BUILD);
  1260. if(!usage)
  1261. {
  1262. slist.pushBackSprintf("NONE");
  1263. }
  1264. # undef ANKI_BUFF_USAGE
  1265. ANKI_ASSERT(!slist.isEmpty());
  1266. StringAuto str(alloc);
  1267. slist.join(" | ", str);
  1268. return str;
  1269. }
  1270. StringAuto RenderGraph::asUsageToStr(StackAllocator<U8>& alloc, AccelerationStructureUsageBit usage)
  1271. {
  1272. StringListAuto slist(alloc);
  1273. # define ANKI_AS_USAGE(u) \
  1274. if(!!(usage & AccelerationStructureUsageBit::u)) \
  1275. { \
  1276. slist.pushBackSprintf("%s", #u); \
  1277. }
  1278. ANKI_AS_USAGE(BUILD);
  1279. ANKI_AS_USAGE(ATTACH);
  1280. ANKI_AS_USAGE(GEOMETRY_READ);
  1281. ANKI_AS_USAGE(FRAGMENT_READ);
  1282. ANKI_AS_USAGE(COMPUTE_READ);
  1283. ANKI_AS_USAGE(TRACE_RAYS_READ);
  1284. if(!usage)
  1285. {
  1286. slist.pushBackSprintf("NONE");
  1287. }
  1288. # undef ANKI_AS_USAGE
  1289. ANKI_ASSERT(!slist.isEmpty());
  1290. StringAuto str(alloc);
  1291. slist.join(" | ", str);
  1292. return str;
  1293. }
  1294. Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, const BakeContext& ctx,
  1295. CString path) const
  1296. {
  1297. ANKI_GR_LOGW("Running with debug code");
  1298. static const Array<const char*, 5> COLORS = {"red", "green", "blue", "magenta", "cyan"};
  1299. auto alloc = ctx.m_alloc;
  1300. StringListAuto slist(alloc);
  1301. slist.pushBackSprintf("digraph {\n");
  1302. slist.pushBackSprintf("\t//splines = ortho;\nconcentrate = true;\n");
  1303. for(U32 batchIdx = 0; batchIdx < ctx.m_batches.getSize(); ++batchIdx)
  1304. {
  1305. // Set same rank
  1306. slist.pushBackSprintf("\t{rank=\"same\";");
  1307. for(U32 passIdx : ctx.m_batches[batchIdx].m_passIndices)
  1308. {
  1309. slist.pushBackSprintf("\"%s\";", descr.m_passes[passIdx]->m_name.cstr());
  1310. }
  1311. slist.pushBackSprintf("}\n");
  1312. // Print passes
  1313. for(U32 passIdx : ctx.m_batches[batchIdx].m_passIndices)
  1314. {
  1315. CString passName = descr.m_passes[passIdx]->m_name.toCString();
  1316. slist.pushBackSprintf(
  1317. "\t\"%s\"[color=%s,style=%s,shape=box];\n", passName.cstr(), COLORS[batchIdx % COLORS.getSize()],
  1318. (descr.m_passes[passIdx]->m_type == RenderPassDescriptionBase::Type::GRAPHICS) ? "bold" : "dashed");
  1319. for(U32 depIdx : ctx.m_passes[passIdx].m_dependsOn)
  1320. {
  1321. slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", descr.m_passes[depIdx]->m_name.cstr(), passName.cstr());
  1322. }
  1323. if(ctx.m_passes[passIdx].m_dependsOn.getSize() == 0)
  1324. {
  1325. slist.pushBackSprintf("\tNONE->\"%s\";\n", descr.m_passes[passIdx]->m_name.cstr());
  1326. }
  1327. }
  1328. }
  1329. # if 0
  1330. // Color the resources
  1331. slist.pushBackSprintf("subgraph cluster_0 {\n");
  1332. for(U rtIdx = 0; rtIdx < descr.m_renderTargets.getSize(); ++rtIdx)
  1333. {
  1334. slist.pushBackSprintf(
  1335. "\t\"%s\"[color=%s];\n", &descr.m_renderTargets[rtIdx].m_name[0], COLORS[rtIdx % COLORS.getSize()]);
  1336. }
  1337. slist.pushBackSprintf("}\n");
  1338. # endif
  1339. // Barriers
  1340. // slist.pushBackSprintf("subgraph cluster_1 {\n");
  1341. StringAuto prevBubble(ctx.m_alloc);
  1342. prevBubble.create("START");
  1343. for(U32 batchIdx = 0; batchIdx < ctx.m_batches.getSize(); ++batchIdx)
  1344. {
  1345. const Batch& batch = ctx.m_batches[batchIdx];
  1346. StringAuto batchName(ctx.m_alloc);
  1347. batchName.sprintf("batch%u", batchIdx);
  1348. for(U32 barrierIdx = 0; barrierIdx < batch.m_textureBarriersBefore.getSize(); ++barrierIdx)
  1349. {
  1350. const TextureBarrier& barrier = batch.m_textureBarriersBefore[barrierIdx];
  1351. StringAuto barrierLabel(ctx.m_alloc);
  1352. barrierLabel.sprintf("<b>%s</b> (mip,dp,f,l)=(%u,%u,%u,%u)<br/>%s <b>to</b> %s",
  1353. &descr.m_renderTargets[barrier.m_idx].m_name[0], barrier.m_surface.m_level,
  1354. barrier.m_surface.m_depth, barrier.m_surface.m_face, barrier.m_surface.m_layer,
  1355. textureUsageToStr(alloc, barrier.m_usageBefore).cstr(),
  1356. textureUsageToStr(alloc, barrier.m_usageAfter).cstr());
  1357. StringAuto barrierName(ctx.m_alloc);
  1358. barrierName.sprintf("%s tex barrier%u", batchName.cstr(), barrierIdx);
  1359. slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
  1360. COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
  1361. slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
  1362. prevBubble = barrierName;
  1363. }
  1364. for(U32 barrierIdx = 0; barrierIdx < batch.m_bufferBarriersBefore.getSize(); ++barrierIdx)
  1365. {
  1366. const BufferBarrier& barrier = batch.m_bufferBarriersBefore[barrierIdx];
  1367. StringAuto barrierLabel(ctx.m_alloc);
  1368. barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", &descr.m_buffers[barrier.m_idx].m_name[0],
  1369. bufferUsageToStr(alloc, barrier.m_usageBefore).cstr(),
  1370. bufferUsageToStr(alloc, barrier.m_usageAfter).cstr());
  1371. StringAuto barrierName(ctx.m_alloc);
  1372. barrierName.sprintf("%s buff barrier%u", batchName.cstr(), barrierIdx);
  1373. slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
  1374. COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
  1375. slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
  1376. prevBubble = barrierName;
  1377. }
  1378. for(U32 barrierIdx = 0; barrierIdx < batch.m_asBarriersBefore.getSize(); ++barrierIdx)
  1379. {
  1380. const ASBarrier& barrier = batch.m_asBarriersBefore[barrierIdx];
  1381. StringAuto barrierLabel(ctx.m_alloc);
  1382. barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", descr.m_as[barrier.m_idx].m_name.getBegin(),
  1383. asUsageToStr(alloc, barrier.m_usageBefore).cstr(),
  1384. asUsageToStr(alloc, barrier.m_usageAfter).cstr());
  1385. StringAuto barrierName(ctx.m_alloc);
  1386. barrierName.sprintf("%s AS barrier%u", batchName.cstr(), barrierIdx);
  1387. slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
  1388. COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
  1389. slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
  1390. prevBubble = barrierName;
  1391. }
  1392. for(U32 passIdx : batch.m_passIndices)
  1393. {
  1394. const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
  1395. StringAuto passName(alloc);
  1396. passName.sprintf("%s pass", pass.m_name.cstr());
  1397. slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold];\n", passName.cstr(),
  1398. COLORS[batchIdx % COLORS.getSize()]);
  1399. slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), passName.cstr());
  1400. prevBubble = passName;
  1401. }
  1402. }
  1403. // slist.pushBackSprintf("}\n");
  1404. slist.pushBackSprintf("}");
  1405. File file;
  1406. ANKI_CHECK(file.open(StringAuto(alloc).sprintf("%s/rgraph_%05u.dot", &path[0], m_version).toCString(),
  1407. FileOpenFlag::WRITE));
  1408. for(const String& s : slist)
  1409. {
  1410. ANKI_CHECK(file.writeText("%s", &s[0]));
  1411. }
  1412. return Error::NONE;
  1413. }
  1414. #endif
  1415. } // end namespace anki