RenderGraph.cpp 51 KB

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