RenderGraph.cpp 51 KB

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