RenderGraph.cpp 51 KB

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