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. {
  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. RenderPassWorkCallback m_callback;
  99. void* m_userData;
  100. DynamicArray<CommandBufferPtr> m_secondLevelCmdbs;
  101. /// Will reuse the m_secondLevelCmdbInitInfo.m_framebuffer to get the framebuffer.
  102. CommandBufferInitInfo m_secondLevelCmdbInitInfo;
  103. Array<U32, 4> m_fbRenderArea;
  104. Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS> m_colorUsages = {}; ///< For beginRender pass
  105. TextureUsageBit m_dsUsage = TextureUsageBit::NONE; ///< For beginRender pass
  106. U32 m_batchIdx ANKI_DEBUG_CODE(= MAX_U32);
  107. Bool m_drawsToPresentable = false;
  108. FramebufferPtr& fb()
  109. {
  110. return m_secondLevelCmdbInitInfo.m_framebuffer;
  111. }
  112. const FramebufferPtr& fb() const
  113. {
  114. return m_secondLevelCmdbInitInfo.m_framebuffer;
  115. }
  116. };
  117. /// A batch of render passes. These passes can run in parallel.
  118. /// @warning It's POD. Destructor won't be called.
  119. class RenderGraph::Batch
  120. {
  121. public:
  122. DynamicArray<U32> m_passIndices;
  123. DynamicArray<TextureBarrier> m_textureBarriersBefore;
  124. DynamicArray<BufferBarrier> m_bufferBarriersBefore;
  125. DynamicArray<ASBarrier> m_asBarriersBefore;
  126. CommandBuffer* m_cmdb; ///< Someone else holds the ref already so have a ptr here.
  127. };
  128. /// The RenderGraph build context.
  129. class RenderGraph::BakeContext
  130. {
  131. public:
  132. StackAllocator<U8> m_alloc;
  133. DynamicArray<Pass> m_passes;
  134. BitSet<MAX_RENDER_GRAPH_PASSES, U64> m_passIsInBatch{false};
  135. DynamicArray<Batch> m_batches;
  136. DynamicArray<RT> m_rts;
  137. DynamicArray<Buffer> m_buffers;
  138. DynamicArray<AS> m_as;
  139. DynamicArray<CommandBufferPtr> m_graphicsCmdbs;
  140. Bool m_gatherStatistics = false;
  141. BakeContext(const StackAllocator<U8>& alloc)
  142. : m_alloc(alloc)
  143. {
  144. }
  145. };
  146. void FramebufferDescription::bake()
  147. {
  148. ANKI_ASSERT(m_hash == 0 && "Already baked");
  149. m_hash = 0;
  150. ANKI_ASSERT(m_colorAttachmentCount > 0 || !!m_depthStencilAttachment.m_aspect);
  151. // First the depth attachments
  152. if(m_colorAttachmentCount)
  153. {
  154. ANKI_BEGIN_PACKED_STRUCT
  155. struct ColorAttachment
  156. {
  157. TextureSurfaceInfo m_surf;
  158. U32 m_loadOp;
  159. U32 m_storeOp;
  160. Array<U32, 4> m_clearColor;
  161. };
  162. ANKI_END_PACKED_STRUCT
  163. static_assert(sizeof(ColorAttachment) == 4 * (4 + 1 + 1 + 4), "Wrong size");
  164. Array<ColorAttachment, MAX_COLOR_ATTACHMENTS> colorAttachments;
  165. for(U i = 0; i < m_colorAttachmentCount; ++i)
  166. {
  167. const FramebufferDescriptionAttachment& inAtt = m_colorAttachments[i];
  168. colorAttachments[i].m_surf = inAtt.m_surface;
  169. colorAttachments[i].m_loadOp = static_cast<U32>(inAtt.m_loadOperation);
  170. colorAttachments[i].m_storeOp = static_cast<U32>(inAtt.m_storeOperation);
  171. memcpy(&colorAttachments[i].m_clearColor[0], &inAtt.m_clearValue.m_coloru[0], sizeof(U32) * 4);
  172. }
  173. m_hash = computeHash(&colorAttachments[0], sizeof(ColorAttachment) * m_colorAttachmentCount);
  174. }
  175. // DS attachment
  176. if(!!m_depthStencilAttachment.m_aspect)
  177. {
  178. ANKI_BEGIN_PACKED_STRUCT
  179. struct DSAttachment
  180. {
  181. TextureSurfaceInfo m_surf;
  182. U32 m_loadOp;
  183. U32 m_storeOp;
  184. U32 m_stencilLoadOp;
  185. U32 m_stencilStoreOp;
  186. U32 m_aspect;
  187. F32 m_depthClear;
  188. I32 m_stencilClear;
  189. } outAtt;
  190. ANKI_END_PACKED_STRUCT
  191. const FramebufferDescriptionAttachment& inAtt = m_depthStencilAttachment;
  192. const Bool hasDepth = !!(inAtt.m_aspect & DepthStencilAspectBit::DEPTH);
  193. const Bool hasStencil = !!(inAtt.m_aspect & DepthStencilAspectBit::STENCIL);
  194. outAtt.m_surf = inAtt.m_surface;
  195. outAtt.m_loadOp = (hasDepth) ? static_cast<U32>(inAtt.m_loadOperation) : 0;
  196. outAtt.m_storeOp = (hasDepth) ? static_cast<U32>(inAtt.m_storeOperation) : 0;
  197. outAtt.m_stencilLoadOp = (hasStencil) ? static_cast<U32>(inAtt.m_stencilLoadOperation) : 0;
  198. outAtt.m_stencilStoreOp = (hasStencil) ? static_cast<U32>(inAtt.m_stencilStoreOperation) : 0;
  199. outAtt.m_aspect = static_cast<U32>(inAtt.m_aspect);
  200. outAtt.m_depthClear = (hasDepth) ? inAtt.m_clearValue.m_depthStencil.m_depth : 0.0f;
  201. outAtt.m_stencilClear = (hasStencil) ? inAtt.m_clearValue.m_depthStencil.m_stencil : 0;
  202. m_hash = (m_hash != 0) ? appendHash(&outAtt, sizeof(outAtt), m_hash) : computeHash(&outAtt, sizeof(outAtt));
  203. }
  204. ANKI_ASSERT(m_hash != 0 && m_hash != 1);
  205. }
  206. RenderGraph::RenderGraph(GrManager* manager, CString name)
  207. : GrObject(manager, CLASS_TYPE, name)
  208. {
  209. ANKI_ASSERT(manager);
  210. }
  211. RenderGraph::~RenderGraph()
  212. {
  213. ANKI_ASSERT(m_ctx == nullptr);
  214. while(!m_renderTargetCache.isEmpty())
  215. {
  216. auto it = m_renderTargetCache.getBegin();
  217. RenderTargetCacheEntry& entry = *it;
  218. entry.m_textures.destroy(getAllocator());
  219. m_renderTargetCache.erase(getAllocator(), it);
  220. }
  221. m_fbCache.destroy(getAllocator());
  222. for(auto& it : m_importedRenderTargets)
  223. {
  224. it.m_surfOrVolLastUsages.destroy(getAllocator());
  225. }
  226. m_importedRenderTargets.destroy(getAllocator());
  227. }
  228. RenderGraph* RenderGraph::newInstance(GrManager* manager)
  229. {
  230. return manager->getAllocator().newInstance<RenderGraph>(manager, "N/A");
  231. }
  232. void RenderGraph::reset()
  233. {
  234. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_RESET);
  235. if(!m_ctx)
  236. {
  237. return;
  238. }
  239. if((m_version % PERIODIC_CLEANUP_EVERY) == 0)
  240. {
  241. // Do cleanup
  242. periodicCleanup();
  243. }
  244. // Extract the final usage of the imported RTs and clean all RTs
  245. for(RT& rt : m_ctx->m_rts)
  246. {
  247. if(rt.m_imported)
  248. {
  249. const U32 surfOrVolumeCount = getTextureSurfOrVolCount(rt.m_texture);
  250. // Create a new hash because our hash map dislikes concurent keys.
  251. const U64 uuid = rt.m_texture->getUuid();
  252. const U64 hash = computeHash(&uuid, sizeof(uuid));
  253. auto it = m_importedRenderTargets.find(hash);
  254. if(it != m_importedRenderTargets.getEnd())
  255. {
  256. // Found
  257. ANKI_ASSERT(it->m_surfOrVolLastUsages.getSize() == surfOrVolumeCount);
  258. ANKI_ASSERT(rt.m_surfOrVolUsages.getSize() == surfOrVolumeCount);
  259. }
  260. else
  261. {
  262. // Not found, create
  263. it = m_importedRenderTargets.emplace(getAllocator(), hash);
  264. it->m_surfOrVolLastUsages.create(getAllocator(), surfOrVolumeCount);
  265. }
  266. // Update the usage
  267. for(U32 surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
  268. {
  269. it->m_surfOrVolLastUsages[surfOrVolIdx] = rt.m_surfOrVolUsages[surfOrVolIdx];
  270. }
  271. }
  272. rt.m_texture.reset(nullptr);
  273. }
  274. for(Buffer& buff : m_ctx->m_buffers)
  275. {
  276. buff.m_buffer.reset(nullptr);
  277. }
  278. for(AS& as : m_ctx->m_as)
  279. {
  280. as.m_as.reset(nullptr);
  281. }
  282. for(auto& it : m_renderTargetCache)
  283. {
  284. it.m_texturesInUse = 0;
  285. }
  286. for(Pass& p : m_ctx->m_passes)
  287. {
  288. p.fb().reset(nullptr);
  289. p.m_secondLevelCmdbs.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 = inPass.m_callback;
  632. outPass.m_userData = inPass.m_userData;
  633. // Create consumer info
  634. outPass.m_consumedTextures.resize(alloc, inPass.m_rtDeps.getSize());
  635. for(U32 depIdx = 0; depIdx < inPass.m_rtDeps.getSize(); ++depIdx)
  636. {
  637. const RenderPassDependency& inDep = inPass.m_rtDeps[depIdx];
  638. ANKI_ASSERT(inDep.m_type == RenderPassDependency::Type::TEXTURE);
  639. RenderPassDependency::TextureInfo& inf = outPass.m_consumedTextures[depIdx];
  640. ANKI_ASSERT(sizeof(inf) == sizeof(inDep.m_texture));
  641. memcpy(&inf, &inDep.m_texture, sizeof(inf));
  642. }
  643. // Create command buffers and framebuffer
  644. if(inPass.m_type == RenderPassDescriptionBase::Type::GRAPHICS)
  645. {
  646. const GraphicsRenderPassDescription& graphicsPass =
  647. static_cast<const GraphicsRenderPassDescription&>(inPass);
  648. if(graphicsPass.hasFramebuffer())
  649. {
  650. Bool drawsToPresentable;
  651. outPass.fb() = getOrCreateFramebuffer(graphicsPass.m_fbDescr, &graphicsPass.m_rtHandles[0],
  652. inPass.m_name.cstr(), drawsToPresentable);
  653. outPass.m_fbRenderArea = graphicsPass.m_fbRenderArea;
  654. outPass.m_drawsToPresentable = drawsToPresentable;
  655. }
  656. else
  657. {
  658. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  659. }
  660. }
  661. else
  662. {
  663. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  664. }
  665. // Set dependencies by checking all previous subpasses.
  666. U32 prevPassIdx = passIdx;
  667. while(prevPassIdx--)
  668. {
  669. const RenderPassDescriptionBase& prevPass = *descr.m_passes[prevPassIdx];
  670. if(passADependsOnB(inPass, prevPass))
  671. {
  672. outPass.m_dependsOn.emplaceBack(alloc, prevPassIdx);
  673. }
  674. }
  675. }
  676. }
  677. void RenderGraph::initBatches()
  678. {
  679. ANKI_ASSERT(m_ctx);
  680. U passesAssignedToBatchCount = 0;
  681. const U passCount = m_ctx->m_passes.getSize();
  682. ANKI_ASSERT(passCount > 0);
  683. Bool setTimestamp = m_ctx->m_gatherStatistics;
  684. while(passesAssignedToBatchCount < passCount)
  685. {
  686. m_ctx->m_batches.emplaceBack(m_ctx->m_alloc);
  687. Batch& batch = m_ctx->m_batches.getBack();
  688. Bool drawsToPresentable = false;
  689. for(U32 i = 0; i < passCount; ++i)
  690. {
  691. if(!m_ctx->m_passIsInBatch.get(i) && !passHasUnmetDependencies(*m_ctx, i))
  692. {
  693. // Add to the batch
  694. ++passesAssignedToBatchCount;
  695. batch.m_passIndices.emplaceBack(m_ctx->m_alloc, i);
  696. // Will batch draw to the swapchain?
  697. drawsToPresentable = drawsToPresentable || m_ctx->m_passes[i].m_drawsToPresentable;
  698. }
  699. }
  700. // Get or create cmdb for the batch.
  701. // Create a new cmdb if the batch is writing to swapchain. This will help Vulkan to have a dependency of the
  702. // swap chain image acquire to the 2nd command buffer instead of adding it to a single big cmdb.
  703. if(m_ctx->m_graphicsCmdbs.isEmpty() || drawsToPresentable)
  704. {
  705. CommandBufferInitInfo cmdbInit;
  706. cmdbInit.m_flags = CommandBufferFlag::GENERAL_WORK;
  707. CommandBufferPtr cmdb = getManager().newCommandBuffer(cmdbInit);
  708. m_ctx->m_graphicsCmdbs.emplaceBack(m_ctx->m_alloc, cmdb);
  709. batch.m_cmdb = cmdb.get();
  710. // Maybe write a timestamp
  711. if(ANKI_UNLIKELY(setTimestamp))
  712. {
  713. setTimestamp = false;
  714. TimestampQueryPtr query = getManager().newTimestampQuery();
  715. cmdb->resetTimestampQuery(query);
  716. cmdb->writeTimestamp(query);
  717. m_statistics.m_nextTimestamp = (m_statistics.m_nextTimestamp + 1) % MAX_TIMESTAMPS_BUFFERED;
  718. m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2] = query;
  719. }
  720. }
  721. else
  722. {
  723. batch.m_cmdb = m_ctx->m_graphicsCmdbs.getBack().get();
  724. }
  725. // Mark batch's passes done
  726. for(U32 passIdx : m_ctx->m_batches.getBack().m_passIndices)
  727. {
  728. m_ctx->m_passIsInBatch.set(passIdx);
  729. m_ctx->m_passes[passIdx].m_batchIdx = m_ctx->m_batches.getSize() - 1;
  730. }
  731. }
  732. }
  733. void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  734. {
  735. BakeContext& ctx = *m_ctx;
  736. const U32 passCount = descr.m_passes.getSize();
  737. ANKI_ASSERT(passCount > 0);
  738. for(U32 passIdx = 0; passIdx < passCount; ++passIdx)
  739. {
  740. const RenderPassDescriptionBase& inPass = *descr.m_passes[passIdx];
  741. Pass& outPass = ctx.m_passes[passIdx];
  742. // Create command buffers and framebuffer
  743. if(inPass.m_type == RenderPassDescriptionBase::Type::GRAPHICS)
  744. {
  745. const GraphicsRenderPassDescription& graphicsPass =
  746. static_cast<const GraphicsRenderPassDescription&>(inPass);
  747. if(graphicsPass.hasFramebuffer())
  748. {
  749. // Init the usage bits
  750. TextureUsageBit usage;
  751. for(U i = 0; i < graphicsPass.m_fbDescr.m_colorAttachmentCount; ++i)
  752. {
  753. getCrntUsage(graphicsPass.m_rtHandles[i], outPass.m_batchIdx,
  754. TextureSubresourceInfo(graphicsPass.m_fbDescr.m_colorAttachments[i].m_surface), usage);
  755. outPass.m_colorUsages[i] = usage;
  756. }
  757. if(!!graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect)
  758. {
  759. TextureSubresourceInfo subresource =
  760. TextureSubresourceInfo(graphicsPass.m_fbDescr.m_depthStencilAttachment.m_surface,
  761. graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect);
  762. getCrntUsage(graphicsPass.m_rtHandles[MAX_COLOR_ATTACHMENTS], outPass.m_batchIdx, subresource,
  763. usage);
  764. outPass.m_dsUsage = usage;
  765. }
  766. // Do some pre-work for the second level command buffers
  767. if(inPass.m_secondLevelCmdbsCount)
  768. {
  769. outPass.m_secondLevelCmdbs.create(alloc, inPass.m_secondLevelCmdbsCount);
  770. CommandBufferInitInfo& cmdbInit = outPass.m_secondLevelCmdbInitInfo;
  771. cmdbInit.m_flags = CommandBufferFlag::GENERAL_WORK | CommandBufferFlag::SECOND_LEVEL;
  772. ANKI_ASSERT(cmdbInit.m_framebuffer.isCreated());
  773. cmdbInit.m_colorAttachmentUsages = outPass.m_colorUsages;
  774. cmdbInit.m_depthStencilAttachmentUsage = outPass.m_dsUsage;
  775. }
  776. }
  777. else
  778. {
  779. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  780. }
  781. }
  782. else
  783. {
  784. ANKI_ASSERT(inPass.m_secondLevelCmdbsCount == 0 && "Can't have second level cmdbs");
  785. }
  786. }
  787. }
  788. template<typename TFunc>
  789. void RenderGraph::iterateSurfsOrVolumes(const TexturePtr& tex, const TextureSubresourceInfo& subresource, TFunc func)
  790. {
  791. for(U32 mip = subresource.m_firstMipmap; mip < subresource.m_firstMipmap + subresource.m_mipmapCount; ++mip)
  792. {
  793. for(U32 layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount; ++layer)
  794. {
  795. for(U32 face = subresource.m_firstFace; face < U32(subresource.m_firstFace + subresource.m_faceCount);
  796. ++face)
  797. {
  798. // Compute surf or vol idx
  799. const U32 faceCount = textureTypeIsCube(tex->getTextureType()) ? 6 : 1;
  800. const U32 idx = (faceCount * tex->getLayerCount()) * mip + faceCount * layer + face;
  801. const TextureSurfaceInfo surf(mip, 0, face, layer);
  802. if(!func(idx, surf))
  803. {
  804. return;
  805. }
  806. }
  807. }
  808. }
  809. }
  810. void RenderGraph::setTextureBarrier(Batch& batch, const RenderPassDependency& dep)
  811. {
  812. ANKI_ASSERT(dep.m_type == RenderPassDependency::Type::TEXTURE);
  813. BakeContext& ctx = *m_ctx;
  814. const U32 batchIdx = U32(&batch - &ctx.m_batches[0]);
  815. const U32 rtIdx = dep.m_texture.m_handle.m_idx;
  816. const TextureUsageBit depUsage = dep.m_texture.m_usage;
  817. RT& rt = ctx.m_rts[rtIdx];
  818. iterateSurfsOrVolumes(
  819. rt.m_texture, dep.m_texture.m_subresource, [&](U32 surfOrVolIdx, const TextureSurfaceInfo& surf) {
  820. TextureUsageBit& crntUsage = rt.m_surfOrVolUsages[surfOrVolIdx];
  821. if(crntUsage != depUsage)
  822. {
  823. // Check if we can merge barriers
  824. if(rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] == batchIdx)
  825. {
  826. // Will merge the barriers
  827. crntUsage |= depUsage;
  828. Bool found = false;
  829. for(TextureBarrier& b : batch.m_textureBarriersBefore)
  830. {
  831. if(b.m_idx == rtIdx && b.m_surface == surf)
  832. {
  833. b.m_usageAfter |= depUsage;
  834. found = true;
  835. break;
  836. }
  837. }
  838. (void)found;
  839. ANKI_ASSERT(found);
  840. }
  841. else
  842. {
  843. // Create a new barrier for this surface
  844. batch.m_textureBarriersBefore.emplaceBack(ctx.m_alloc, rtIdx, crntUsage, depUsage, surf);
  845. crntUsage = depUsage;
  846. rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] = U16(batchIdx);
  847. }
  848. }
  849. return true;
  850. });
  851. }
  852. void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr)
  853. {
  854. BakeContext& ctx = *m_ctx;
  855. const StackAllocator<U8>& alloc = ctx.m_alloc;
  856. // For all batches
  857. for(Batch& batch : ctx.m_batches)
  858. {
  859. BitSet<MAX_RENDER_GRAPH_BUFFERS, U64> buffHasBarrierMask(false);
  860. BitSet<MAX_RENDER_GRAPH_ACCELERATION_STRUCTURES, U32> asHasBarrierMask(false);
  861. // For all passes of that batch
  862. for(U32 passIdx : batch.m_passIndices)
  863. {
  864. const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
  865. // Do textures
  866. for(const RenderPassDependency& dep : pass.m_rtDeps)
  867. {
  868. setTextureBarrier(batch, dep);
  869. }
  870. // Do buffers
  871. for(const RenderPassDependency& dep : pass.m_buffDeps)
  872. {
  873. const U32 buffIdx = dep.m_buffer.m_handle.m_idx;
  874. const BufferUsageBit depUsage = dep.m_buffer.m_usage;
  875. BufferUsageBit& crntUsage = ctx.m_buffers[buffIdx].m_usage;
  876. if(depUsage == crntUsage)
  877. {
  878. continue;
  879. }
  880. const Bool buffHasBarrier = buffHasBarrierMask.get(buffIdx);
  881. if(!buffHasBarrier)
  882. {
  883. // Buff hasn't had a barrier in this batch, add a new barrier
  884. batch.m_bufferBarriersBefore.emplaceBack(alloc, buffIdx, crntUsage, depUsage);
  885. crntUsage = depUsage;
  886. buffHasBarrierMask.set(buffIdx);
  887. }
  888. else
  889. {
  890. // Buff already in a barrier, merge the 2 barriers
  891. BufferBarrier* barrierToMergeTo = nullptr;
  892. for(BufferBarrier& b : batch.m_bufferBarriersBefore)
  893. {
  894. if(b.m_idx == buffIdx)
  895. {
  896. barrierToMergeTo = &b;
  897. break;
  898. }
  899. }
  900. ANKI_ASSERT(barrierToMergeTo);
  901. ANKI_ASSERT(!!barrierToMergeTo->m_usageAfter);
  902. barrierToMergeTo->m_usageAfter |= depUsage;
  903. crntUsage = barrierToMergeTo->m_usageAfter;
  904. }
  905. }
  906. // Do AS
  907. for(const RenderPassDependency& dep : pass.m_asDeps)
  908. {
  909. const U32 asIdx = dep.m_as.m_handle.m_idx;
  910. const AccelerationStructureUsageBit depUsage = dep.m_as.m_usage;
  911. AccelerationStructureUsageBit& crntUsage = ctx.m_as[asIdx].m_usage;
  912. if(depUsage == crntUsage)
  913. {
  914. continue;
  915. }
  916. const Bool asHasBarrierInThisBatch = asHasBarrierMask.get(asIdx);
  917. if(!asHasBarrierInThisBatch)
  918. {
  919. // AS doesn't have a barrier in this batch, create a new one
  920. batch.m_asBarriersBefore.emplaceBack(alloc, asIdx, crntUsage, depUsage);
  921. crntUsage = depUsage;
  922. asHasBarrierMask.set(asIdx);
  923. }
  924. else
  925. {
  926. // AS already has a barrier, merge the 2 barriers
  927. ASBarrier* barrierToMergeTo = nullptr;
  928. for(ASBarrier& other : batch.m_asBarriersBefore)
  929. {
  930. if(other.m_idx == asIdx)
  931. {
  932. barrierToMergeTo = &other;
  933. break;
  934. }
  935. }
  936. ANKI_ASSERT(barrierToMergeTo);
  937. ANKI_ASSERT(!!barrierToMergeTo->m_usageAfter);
  938. barrierToMergeTo->m_usageAfter |= depUsage;
  939. crntUsage = barrierToMergeTo->m_usageAfter;
  940. }
  941. }
  942. } // For all passes
  943. #if ANKI_DBG_RENDER_GRAPH
  944. // Sort the barriers to ease the dumped graph
  945. std::sort(batch.m_textureBarriersBefore.getBegin(), batch.m_textureBarriersBefore.getEnd(),
  946. [&](const TextureBarrier& a, const TextureBarrier& b) {
  947. const U aidx = a.m_idx;
  948. const U bidx = b.m_idx;
  949. if(aidx == bidx)
  950. {
  951. if(a.m_surface.m_level != b.m_surface.m_level)
  952. {
  953. return a.m_surface.m_level < b.m_surface.m_level;
  954. }
  955. else if(a.m_surface.m_face != b.m_surface.m_face)
  956. {
  957. return a.m_surface.m_face < b.m_surface.m_face;
  958. }
  959. else if(a.m_surface.m_layer != b.m_surface.m_layer)
  960. {
  961. return a.m_surface.m_layer < b.m_surface.m_layer;
  962. }
  963. else
  964. {
  965. return false;
  966. }
  967. }
  968. else
  969. {
  970. return aidx < bidx;
  971. }
  972. });
  973. std::sort(batch.m_bufferBarriersBefore.getBegin(), batch.m_bufferBarriersBefore.getEnd(),
  974. [&](const BufferBarrier& a, const BufferBarrier& b) { return a.m_idx < b.m_idx; });
  975. std::sort(batch.m_asBarriersBefore.getBegin(), batch.m_asBarriersBefore.getEnd(),
  976. [&](const ASBarrier& a, const ASBarrier& b) { return a.m_idx < b.m_idx; });
  977. #endif
  978. } // For all batches
  979. }
  980. void RenderGraph::compileNewGraph(const RenderGraphDescription& descr, StackAllocator<U8>& alloc)
  981. {
  982. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_COMPILE);
  983. // Init the context
  984. BakeContext& ctx = *newContext(descr, alloc);
  985. m_ctx = &ctx;
  986. // Init the passes and find the dependencies between passes
  987. initRenderPassesAndSetDeps(descr, alloc);
  988. // Walk the graph and create pass batches
  989. initBatches();
  990. // Now that we know the batches every pass belongs init the graphics passes
  991. initGraphicsPasses(descr, alloc);
  992. // Create barriers between batches
  993. setBatchBarriers(descr);
  994. #if ANKI_DBG_RENDER_GRAPH
  995. if(dumpDependencyDotFile(descr, ctx, "./"))
  996. {
  997. ANKI_LOGF("Won't recover on debug code");
  998. }
  999. #endif
  1000. }
  1001. TexturePtr RenderGraph::getTexture(RenderTargetHandle handle) const
  1002. {
  1003. ANKI_ASSERT(m_ctx->m_rts[handle.m_idx].m_texture.isCreated());
  1004. return m_ctx->m_rts[handle.m_idx].m_texture;
  1005. }
  1006. BufferPtr RenderGraph::getBuffer(BufferHandle handle) const
  1007. {
  1008. ANKI_ASSERT(m_ctx->m_buffers[handle.m_idx].m_buffer.isCreated());
  1009. return m_ctx->m_buffers[handle.m_idx].m_buffer;
  1010. }
  1011. AccelerationStructurePtr RenderGraph::getAs(AccelerationStructureHandle handle) const
  1012. {
  1013. ANKI_ASSERT(m_ctx->m_as[handle.m_idx].m_as.isCreated());
  1014. return m_ctx->m_as[handle.m_idx].m_as;
  1015. }
  1016. void RenderGraph::runSecondLevel(U32 threadIdx)
  1017. {
  1018. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_2ND_LEVEL);
  1019. ANKI_ASSERT(m_ctx);
  1020. RenderPassWorkContext ctx;
  1021. ctx.m_rgraph = this;
  1022. ctx.m_currentSecondLevelCommandBufferIndex = threadIdx;
  1023. for(Pass& p : m_ctx->m_passes)
  1024. {
  1025. const U32 size = p.m_secondLevelCmdbs.getSize();
  1026. if(threadIdx < size)
  1027. {
  1028. ANKI_ASSERT(!p.m_secondLevelCmdbs[threadIdx].isCreated());
  1029. p.m_secondLevelCmdbs[threadIdx] = getManager().newCommandBuffer(p.m_secondLevelCmdbInitInfo);
  1030. ctx.m_commandBuffer = p.m_secondLevelCmdbs[threadIdx];
  1031. ctx.m_secondLevelCommandBufferCount = size;
  1032. ctx.m_passIdx = U32(&p - &m_ctx->m_passes[0]);
  1033. ctx.m_batchIdx = p.m_batchIdx;
  1034. ctx.m_userData = p.m_userData;
  1035. ANKI_ASSERT(ctx.m_commandBuffer.isCreated());
  1036. {
  1037. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_CALLBACK);
  1038. p.m_callback(ctx);
  1039. }
  1040. ctx.m_commandBuffer->flush();
  1041. }
  1042. }
  1043. }
  1044. void RenderGraph::run() const
  1045. {
  1046. ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH_RUN);
  1047. ANKI_ASSERT(m_ctx);
  1048. RenderPassWorkContext ctx;
  1049. ctx.m_rgraph = this;
  1050. ctx.m_currentSecondLevelCommandBufferIndex = 0;
  1051. ctx.m_secondLevelCommandBufferCount = 0;
  1052. for(const Batch& batch : m_ctx->m_batches)
  1053. {
  1054. ctx.m_commandBuffer.reset(batch.m_cmdb);
  1055. CommandBufferPtr& cmdb = ctx.m_commandBuffer;
  1056. // Set the barriers
  1057. for(const TextureBarrier& barrier : batch.m_textureBarriersBefore)
  1058. {
  1059. cmdb->setTextureSurfaceBarrier(m_ctx->m_rts[barrier.m_idx].m_texture, barrier.m_usageBefore,
  1060. barrier.m_usageAfter, barrier.m_surface);
  1061. }
  1062. for(const BufferBarrier& barrier : batch.m_bufferBarriersBefore)
  1063. {
  1064. const Buffer& b = m_ctx->m_buffers[barrier.m_idx];
  1065. cmdb->setBufferBarrier(b.m_buffer, barrier.m_usageBefore, barrier.m_usageAfter, b.m_offset, b.m_range);
  1066. }
  1067. for(const ASBarrier& barrier : batch.m_asBarriersBefore)
  1068. {
  1069. cmdb->setAccelerationStructureBarrier(m_ctx->m_as[barrier.m_idx].m_as, barrier.m_usageBefore,
  1070. barrier.m_usageAfter);
  1071. }
  1072. // Call the passes
  1073. for(U32 passIdx : batch.m_passIndices)
  1074. {
  1075. const Pass& pass = m_ctx->m_passes[passIdx];
  1076. if(pass.fb().isCreated())
  1077. {
  1078. cmdb->beginRenderPass(pass.fb(), pass.m_colorUsages, pass.m_dsUsage, pass.m_fbRenderArea[0],
  1079. pass.m_fbRenderArea[1], pass.m_fbRenderArea[2], pass.m_fbRenderArea[3]);
  1080. }
  1081. const U size = pass.m_secondLevelCmdbs.getSize();
  1082. if(size == 0)
  1083. {
  1084. ctx.m_userData = pass.m_userData;
  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