2
0

RenderGraph.cpp 48 KB

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