IndirectDiffuseProbes.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Renderer/IndirectDiffuseProbes.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/RenderQueue.h>
  8. #include <AnKi/Core/ConfigSet.h>
  9. #include <AnKi/Util/Tracer.h>
  10. #include <AnKi/Collision/Aabb.h>
  11. #include <AnKi/Collision/Functions.h>
  12. namespace anki {
  13. /// Given a cell index compute its world position.
  14. static Vec3 computeProbeCellPosition(U32 cellIdx, const GlobalIlluminationProbeQueueElement& probe)
  15. {
  16. ANKI_ASSERT(cellIdx < probe.m_totalCellCount);
  17. UVec3 cellCoords;
  18. unflatten3dArrayIndex(probe.m_cellCounts.z(), probe.m_cellCounts.y(), probe.m_cellCounts.x(), cellIdx,
  19. cellCoords.z(), cellCoords.y(), cellCoords.x());
  20. const Vec3 halfCellSize = probe.m_cellSizes / 2.0f;
  21. const Vec3 cellPos = Vec3(cellCoords) * probe.m_cellSizes + halfCellSize + probe.m_aabbMin;
  22. ANKI_ASSERT(cellPos < probe.m_aabbMax);
  23. return cellPos;
  24. }
  25. class IndirectDiffuseProbes::InternalContext
  26. {
  27. public:
  28. IndirectDiffuseProbes* m_gi ANKI_DEBUG_CODE(= numberToPtr<IndirectDiffuseProbes*>(1));
  29. RenderingContext* m_ctx ANKI_DEBUG_CODE(= numberToPtr<RenderingContext*>(1));
  30. GlobalIlluminationProbeQueueElement*
  31. m_probeToUpdateThisFrame ANKI_DEBUG_CODE(= numberToPtr<GlobalIlluminationProbeQueueElement*>(1));
  32. UVec3 m_cellOfTheProbeToUpdateThisFrame ANKI_DEBUG_CODE(= UVec3(MAX_U32));
  33. Array<RenderTargetHandle, GBUFFER_COLOR_ATTACHMENT_COUNT> m_gbufferColorRts;
  34. RenderTargetHandle m_gbufferDepthRt;
  35. RenderTargetHandle m_shadowsRt;
  36. RenderTargetHandle m_lightShadingRt;
  37. WeakArray<RenderTargetHandle> m_irradianceProbeRts;
  38. U32 m_gbufferDrawcallCount ANKI_DEBUG_CODE(= MAX_U32);
  39. U32 m_smDrawcallCount ANKI_DEBUG_CODE(= MAX_U32);
  40. static void foo()
  41. {
  42. static_assert(std::is_trivially_destructible<InternalContext>::value, "See file");
  43. }
  44. };
  45. IndirectDiffuseProbes::~IndirectDiffuseProbes()
  46. {
  47. m_cacheEntries.destroy(getAllocator());
  48. m_probeUuidToCacheEntryIdx.destroy(getAllocator());
  49. }
  50. const RenderTargetHandle&
  51. IndirectDiffuseProbes::getVolumeRenderTarget(const GlobalIlluminationProbeQueueElement& probe) const
  52. {
  53. ANKI_ASSERT(m_giCtx);
  54. ANKI_ASSERT(&probe >= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront()
  55. && &probe <= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getBack());
  56. const U32 idx = U32(&probe - &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront());
  57. return m_giCtx->m_irradianceProbeRts[idx];
  58. }
  59. void IndirectDiffuseProbes::setRenderGraphDependencies(const RenderingContext& ctx, RenderPassDescriptionBase& pass,
  60. TextureUsageBit usage) const
  61. {
  62. for(U32 idx = 0; idx < ctx.m_renderQueue->m_giProbes.getSize(); ++idx)
  63. {
  64. pass.newDependency({getVolumeRenderTarget(ctx.m_renderQueue->m_giProbes[idx]), usage});
  65. }
  66. }
  67. void IndirectDiffuseProbes::bindVolumeTextures(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx, U32 set,
  68. U32 binding) const
  69. {
  70. for(U32 idx = 0; idx < MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES; ++idx)
  71. {
  72. if(idx < ctx.m_renderQueue->m_giProbes.getSize())
  73. {
  74. rgraphCtx.bindColorTexture(set, binding, getVolumeRenderTarget(ctx.m_renderQueue->m_giProbes[idx]), idx);
  75. }
  76. else
  77. {
  78. rgraphCtx.m_commandBuffer->bindTexture(set, binding, m_r->getDummyTextureView3d(), idx);
  79. }
  80. }
  81. }
  82. Error IndirectDiffuseProbes::init(const ConfigSet& cfg)
  83. {
  84. ANKI_R_LOGI("Initializing global illumination");
  85. const Error err = initInternal(cfg);
  86. if(err)
  87. {
  88. ANKI_R_LOGE("Failed to initialize global illumination");
  89. }
  90. return err;
  91. }
  92. Error IndirectDiffuseProbes::initInternal(const ConfigSet& cfg)
  93. {
  94. m_tileSize = cfg.getNumberU32("r_giTileResolution");
  95. m_cacheEntries.create(getAllocator(), cfg.getNumberU32("r_giMaxCachedProbes"));
  96. m_maxVisibleProbes = cfg.getNumberU32("r_giMaxVisibleProbes");
  97. ANKI_ASSERT(m_maxVisibleProbes <= MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES);
  98. ANKI_ASSERT(m_cacheEntries.getSize() >= m_maxVisibleProbes);
  99. ANKI_CHECK(initGBuffer(cfg));
  100. ANKI_CHECK(initLightShading(cfg));
  101. ANKI_CHECK(initShadowMapping(cfg));
  102. ANKI_CHECK(initIrradiance(cfg));
  103. return Error::NONE;
  104. }
  105. Error IndirectDiffuseProbes::initGBuffer(const ConfigSet& cfg)
  106. {
  107. // Create RT descriptions
  108. {
  109. RenderTargetDescription texinit = m_r->create2DRenderTargetDescription(
  110. m_tileSize * 6, m_tileSize, GBUFFER_COLOR_ATTACHMENT_PIXEL_FORMATS[0], "GI GBuffer");
  111. // Create color RT descriptions
  112. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  113. {
  114. texinit.m_format = GBUFFER_COLOR_ATTACHMENT_PIXEL_FORMATS[i];
  115. m_gbuffer.m_colorRtDescrs[i] = texinit;
  116. m_gbuffer.m_colorRtDescrs[i].setName(StringAuto(getAllocator()).sprintf("GI GBuff Col #%u", i).toCString());
  117. m_gbuffer.m_colorRtDescrs[i].bake();
  118. }
  119. // Create depth RT
  120. texinit.m_format = GBUFFER_DEPTH_ATTACHMENT_PIXEL_FORMAT;
  121. texinit.setName("GI GBuff Depth");
  122. m_gbuffer.m_depthRtDescr = texinit;
  123. m_gbuffer.m_depthRtDescr.bake();
  124. }
  125. // Create FB descr
  126. {
  127. m_gbuffer.m_fbDescr.m_colorAttachmentCount = GBUFFER_COLOR_ATTACHMENT_COUNT;
  128. for(U j = 0; j < GBUFFER_COLOR_ATTACHMENT_COUNT; ++j)
  129. {
  130. m_gbuffer.m_fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::CLEAR;
  131. }
  132. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  133. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  134. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
  135. m_gbuffer.m_fbDescr.bake();
  136. }
  137. return Error::NONE;
  138. }
  139. Error IndirectDiffuseProbes::initShadowMapping(const ConfigSet& cfg)
  140. {
  141. const U32 resolution = cfg.getNumberU32("r_giShadowMapResolution");
  142. ANKI_ASSERT(resolution > 8);
  143. // RT descr
  144. m_shadowMapping.m_rtDescr =
  145. m_r->create2DRenderTargetDescription(resolution * 6, resolution, Format::D32_SFLOAT, "GI SM");
  146. m_shadowMapping.m_rtDescr.bake();
  147. // FB descr
  148. m_shadowMapping.m_fbDescr.m_colorAttachmentCount = 0;
  149. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  150. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
  151. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  152. m_shadowMapping.m_fbDescr.bake();
  153. // Shadow sampler
  154. {
  155. SamplerInitInfo inf;
  156. inf.m_compareOperation = CompareOperation::LESS_EQUAL;
  157. inf.m_addressing = SamplingAddressing::CLAMP;
  158. inf.m_mipmapFilter = SamplingFilter::BASE;
  159. inf.m_minMagFilter = SamplingFilter::LINEAR;
  160. m_shadowMapping.m_shadowSampler = getGrManager().newSampler(inf);
  161. }
  162. return Error::NONE;
  163. }
  164. Error IndirectDiffuseProbes::initLightShading(const ConfigSet& cfg)
  165. {
  166. // Init RT descr
  167. {
  168. m_lightShading.m_rtDescr = m_r->create2DRenderTargetDescription(
  169. m_tileSize * 6, m_tileSize, LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT, "GI LS");
  170. m_lightShading.m_rtDescr.bake();
  171. }
  172. // Create FB descr
  173. {
  174. m_lightShading.m_fbDescr.m_colorAttachmentCount = 1;
  175. m_lightShading.m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
  176. m_lightShading.m_fbDescr.bake();
  177. }
  178. // Init deferred
  179. ANKI_CHECK(m_lightShading.m_deferred.init());
  180. return Error::NONE;
  181. }
  182. Error IndirectDiffuseProbes::initIrradiance(const ConfigSet& cfg)
  183. {
  184. ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/IrradianceDice.ankiprog", m_irradiance.m_prog));
  185. ShaderProgramResourceVariantInitInfo variantInitInfo(m_irradiance.m_prog);
  186. variantInitInfo.addMutation("WORKGROUP_SIZE_XY", m_tileSize);
  187. variantInitInfo.addMutation("LIGHT_SHADING_TEX", 0);
  188. variantInitInfo.addMutation("STORE_LOCATION", 0);
  189. variantInitInfo.addMutation("SECOND_BOUNCE", 1);
  190. const ShaderProgramResourceVariant* variant;
  191. m_irradiance.m_prog->getOrCreateVariant(variantInitInfo, variant);
  192. m_irradiance.m_grProg = variant->getProgram();
  193. return Error::NONE;
  194. }
  195. void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
  196. {
  197. ANKI_TRACE_SCOPED_EVENT(R_GI);
  198. InternalContext* giCtx = rctx.m_tempAllocator.newInstance<InternalContext>();
  199. m_giCtx = giCtx;
  200. giCtx->m_gi = this;
  201. giCtx->m_ctx = &rctx;
  202. RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
  203. // Prepare the probes
  204. prepareProbes(*giCtx);
  205. const Bool haveProbeToRender = giCtx->m_probeToUpdateThisFrame != nullptr;
  206. if(!haveProbeToRender)
  207. {
  208. // Early exit
  209. return;
  210. }
  211. // Compute task counts for some of the passes
  212. U32 gbufferTaskCount, smTaskCount;
  213. {
  214. giCtx->m_gbufferDrawcallCount = 0;
  215. giCtx->m_smDrawcallCount = 0;
  216. for(const RenderQueue* rq : giCtx->m_probeToUpdateThisFrame->m_renderQueues)
  217. {
  218. ANKI_ASSERT(rq);
  219. giCtx->m_gbufferDrawcallCount += rq->m_renderables.getSize();
  220. if(rq->m_directionalLight.hasShadow())
  221. {
  222. giCtx->m_smDrawcallCount += rq->m_directionalLight.m_shadowRenderQueues[0]->m_renderables.getSize();
  223. }
  224. }
  225. gbufferTaskCount = computeNumberOfSecondLevelCommandBuffers(giCtx->m_gbufferDrawcallCount);
  226. smTaskCount = computeNumberOfSecondLevelCommandBuffers(giCtx->m_smDrawcallCount);
  227. }
  228. // GBuffer
  229. {
  230. // RTs
  231. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  232. {
  233. giCtx->m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
  234. }
  235. giCtx->m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
  236. // Pass
  237. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI gbuff");
  238. pass.setFramebufferInfo(m_gbuffer.m_fbDescr, giCtx->m_gbufferColorRts, giCtx->m_gbufferDepthRt);
  239. pass.setWork(gbufferTaskCount, [this, giCtx](RenderPassWorkContext& rgraphCtx) {
  240. runGBufferInThread(rgraphCtx, *giCtx);
  241. });
  242. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  243. {
  244. pass.newDependency({giCtx->m_gbufferColorRts[i], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  245. }
  246. TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
  247. pass.newDependency({giCtx->m_gbufferDepthRt, TextureUsageBit::ALL_FRAMEBUFFER_ATTACHMENT, subresource});
  248. }
  249. // Shadow pass. Optional
  250. if(giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_uuid
  251. && giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
  252. {
  253. // Update light matrices
  254. for(U i = 0; i < 6; ++i)
  255. {
  256. ANKI_ASSERT(giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_uuid
  257. && giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount
  258. == 1);
  259. const F32 xScale = 1.0f / 6.0f;
  260. const F32 yScale = 1.0f;
  261. const F32 xOffset = F32(i) * (1.0f / 6.0f);
  262. const F32 yOffset = 0.0f;
  263. const Mat4 atlasMtx(xScale, 0.0f, 0.0f, xOffset, 0.0f, yScale, 0.0f, yOffset, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
  264. 0.0f, 0.0f, 1.0f);
  265. Mat4& lightMat =
  266. giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
  267. lightMat = atlasMtx * lightMat;
  268. }
  269. // RT
  270. giCtx->m_shadowsRt = rgraph.newRenderTarget(m_shadowMapping.m_rtDescr);
  271. // Pass
  272. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI SM");
  273. pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, giCtx->m_shadowsRt);
  274. pass.setWork(smTaskCount, [this, giCtx](RenderPassWorkContext& rgraphCtx) {
  275. runShadowmappingInThread(rgraphCtx, *giCtx);
  276. });
  277. TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
  278. pass.newDependency({giCtx->m_shadowsRt, TextureUsageBit::ALL_FRAMEBUFFER_ATTACHMENT, subresource});
  279. }
  280. else
  281. {
  282. giCtx->m_shadowsRt = {};
  283. }
  284. // Light shading pass
  285. {
  286. // RT
  287. giCtx->m_lightShadingRt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);
  288. // Pass
  289. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI LS");
  290. pass.setFramebufferInfo(m_lightShading.m_fbDescr, {{giCtx->m_lightShadingRt}}, {});
  291. pass.setWork(1, [this, giCtx](RenderPassWorkContext& rgraphCtx) {
  292. runLightShading(rgraphCtx, *giCtx);
  293. });
  294. pass.newDependency({giCtx->m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  295. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  296. {
  297. pass.newDependency({giCtx->m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
  298. }
  299. pass.newDependency({giCtx->m_gbufferDepthRt, TextureUsageBit::SAMPLED_FRAGMENT,
  300. TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
  301. if(giCtx->m_shadowsRt.isValid())
  302. {
  303. pass.newDependency({giCtx->m_shadowsRt, TextureUsageBit::SAMPLED_FRAGMENT});
  304. }
  305. }
  306. // Irradiance pass. First & 2nd bounce
  307. {
  308. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI IR");
  309. pass.setWork([this, giCtx](RenderPassWorkContext& rgraphCtx) {
  310. runIrradiance(rgraphCtx, *giCtx);
  311. });
  312. pass.newDependency({giCtx->m_lightShadingRt, TextureUsageBit::SAMPLED_COMPUTE});
  313. for(U32 i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT - 1; ++i)
  314. {
  315. pass.newDependency({giCtx->m_gbufferColorRts[i], TextureUsageBit::SAMPLED_COMPUTE});
  316. }
  317. const U32 probeIdx = U32(giCtx->m_probeToUpdateThisFrame - &giCtx->m_ctx->m_renderQueue->m_giProbes.getFront());
  318. pass.newDependency({giCtx->m_irradianceProbeRts[probeIdx], TextureUsageBit::IMAGE_COMPUTE_WRITE});
  319. }
  320. }
  321. void IndirectDiffuseProbes::prepareProbes(InternalContext& giCtx)
  322. {
  323. RenderingContext& ctx = *giCtx.m_ctx;
  324. giCtx.m_probeToUpdateThisFrame = nullptr;
  325. if(ANKI_UNLIKELY(ctx.m_renderQueue->m_giProbes.getSize() == 0))
  326. {
  327. return;
  328. }
  329. // Iterate the probes and:
  330. // - Find a probe to update this frame
  331. // - Find a probe to update next frame
  332. // - Find the cache entries for each probe
  333. DynamicArray<GlobalIlluminationProbeQueueElement> newListOfProbes;
  334. newListOfProbes.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_giProbes.getSize());
  335. DynamicArray<RenderTargetHandle> volumeRts;
  336. volumeRts.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_giProbes.getSize());
  337. U32 newListOfProbeCount = 0;
  338. Bool foundProbeToUpdateNextFrame = false;
  339. for(U32 probeIdx = 0; probeIdx < ctx.m_renderQueue->m_giProbes.getSize(); ++probeIdx)
  340. {
  341. if(newListOfProbeCount + 1 >= m_maxVisibleProbes)
  342. {
  343. ANKI_R_LOGW("Can't have more that %u visible probes. Increase the r_giMaxVisibleProbes or (somehow) "
  344. "decrease the visible probes",
  345. m_maxVisibleProbes);
  346. break;
  347. }
  348. GlobalIlluminationProbeQueueElement& probe = ctx.m_renderQueue->m_giProbes[probeIdx];
  349. // Find cache entry
  350. const U32 cacheEntryIdx = findBestCacheEntry(probe.m_uuid, m_r->getGlobalTimestamp(), m_cacheEntries,
  351. m_probeUuidToCacheEntryIdx, getAllocator());
  352. if(ANKI_UNLIKELY(cacheEntryIdx == MAX_U32))
  353. {
  354. // Failed
  355. ANKI_R_LOGW("There is not enough space in the indirect lighting atlas for more probes. "
  356. "Increase the r_giMaxCachedProbes or (somehow) decrease the visible probes");
  357. continue;
  358. }
  359. CacheEntry& entry = m_cacheEntries[cacheEntryIdx];
  360. const Bool cacheEntryDirty = entry.m_uuid != probe.m_uuid || entry.m_volumeSize != probe.m_cellCounts
  361. || entry.m_probeAabbMin != probe.m_aabbMin
  362. || entry.m_probeAabbMax != probe.m_aabbMax;
  363. const Bool needsUpdate = cacheEntryDirty || entry.m_renderedCells < probe.m_totalCellCount;
  364. if(ANKI_LIKELY(!needsUpdate))
  365. {
  366. // It's updated, early exit
  367. entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
  368. volumeRts[newListOfProbeCount] =
  369. ctx.m_renderGraphDescr.importRenderTarget(entry.m_volumeTex, TextureUsageBit::SAMPLED_FRAGMENT);
  370. newListOfProbes[newListOfProbeCount++] = probe;
  371. continue;
  372. }
  373. // It needs update
  374. const Bool canUpdateThisFrame = giCtx.m_probeToUpdateThisFrame == nullptr && probe.m_renderQueues[0] != nullptr;
  375. const Bool canUpdateNextFrame = !foundProbeToUpdateNextFrame;
  376. if(!canUpdateThisFrame && canUpdateNextFrame)
  377. {
  378. // Probe will (possibly) be updated next frame, inform the probe
  379. foundProbeToUpdateNextFrame = true;
  380. const U32 cellToRender = (cacheEntryDirty) ? 0 : entry.m_renderedCells;
  381. const Vec3 cellPos = computeProbeCellPosition(cellToRender, probe);
  382. probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData, cellPos.xyz0());
  383. continue;
  384. }
  385. else if(!canUpdateThisFrame)
  386. {
  387. // Can't be updated this frame so remove it from the list
  388. continue;
  389. }
  390. // All good, can use this probe in this frame
  391. if(cacheEntryDirty)
  392. {
  393. entry.m_renderedCells = 0;
  394. entry.m_uuid = probe.m_uuid;
  395. entry.m_probeAabbMin = probe.m_aabbMin;
  396. entry.m_probeAabbMax = probe.m_aabbMax;
  397. entry.m_volumeSize = probe.m_cellCounts;
  398. m_probeUuidToCacheEntryIdx.emplace(getAllocator(), probe.m_uuid, cacheEntryIdx);
  399. }
  400. // Update the cache entry
  401. entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
  402. // Init the cache entry textures
  403. const Bool shouldInitTextures = !entry.m_volumeTex.isCreated() || entry.m_volumeSize != probe.m_cellCounts;
  404. if(shouldInitTextures)
  405. {
  406. TextureInitInfo texInit("GiProbeVolume");
  407. texInit.m_type = TextureType::_3D;
  408. texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
  409. texInit.m_width = probe.m_cellCounts.x() * 6;
  410. texInit.m_height = probe.m_cellCounts.y();
  411. texInit.m_depth = probe.m_cellCounts.z();
  412. texInit.m_usage = TextureUsageBit::ALL_COMPUTE | TextureUsageBit::ALL_SAMPLED;
  413. texInit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
  414. entry.m_volumeTex = m_r->createAndClearRenderTarget(texInit);
  415. }
  416. // Compute the render position
  417. const U32 cellToRender = entry.m_renderedCells++;
  418. ANKI_ASSERT(cellToRender < probe.m_totalCellCount);
  419. unflatten3dArrayIndex(probe.m_cellCounts.z(), probe.m_cellCounts.y(), probe.m_cellCounts.x(), cellToRender,
  420. giCtx.m_cellOfTheProbeToUpdateThisFrame.z(), giCtx.m_cellOfTheProbeToUpdateThisFrame.y(),
  421. giCtx.m_cellOfTheProbeToUpdateThisFrame.x());
  422. // Inform probe about its next frame
  423. if(entry.m_renderedCells == probe.m_totalCellCount)
  424. {
  425. // Don't gather renderables next frame if it's done
  426. probe.m_feedbackCallback(false, probe.m_feedbackCallbackUserData, Vec4(0.0f));
  427. }
  428. else if(!foundProbeToUpdateNextFrame)
  429. {
  430. // Gather rendederables from the same probe next frame
  431. foundProbeToUpdateNextFrame = true;
  432. const Vec3 cellPos = computeProbeCellPosition(entry.m_renderedCells, probe);
  433. probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData, cellPos.xyz0());
  434. }
  435. // Push the probe to the new list
  436. giCtx.m_probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
  437. newListOfProbes[newListOfProbeCount] = probe;
  438. volumeRts[newListOfProbeCount] =
  439. ctx.m_renderGraphDescr.importRenderTarget(entry.m_volumeTex, TextureUsageBit::SAMPLED_FRAGMENT);
  440. ++newListOfProbeCount;
  441. }
  442. // Replace the probe list in the queue
  443. if(newListOfProbeCount > 0)
  444. {
  445. GlobalIlluminationProbeQueueElement* firstProbe;
  446. U32 probeCount, storage;
  447. newListOfProbes.moveAndReset(firstProbe, probeCount, storage);
  448. ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>(firstProbe, newListOfProbeCount);
  449. RenderTargetHandle* firstRt;
  450. volumeRts.moveAndReset(firstRt, probeCount, storage);
  451. m_giCtx->m_irradianceProbeRts = WeakArray<RenderTargetHandle>(firstRt, newListOfProbeCount);
  452. }
  453. else
  454. {
  455. ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>();
  456. newListOfProbes.destroy(ctx.m_tempAllocator);
  457. volumeRts.destroy(ctx.m_tempAllocator);
  458. }
  459. }
  460. void IndirectDiffuseProbes::runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
  461. {
  462. ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
  463. ANKI_TRACE_SCOPED_EVENT(R_GI);
  464. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  465. const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
  466. I32 start, end;
  467. U32 startu, endu;
  468. splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex, rgraphCtx.m_secondLevelCommandBufferCount,
  469. giCtx.m_gbufferDrawcallCount, startu, endu);
  470. start = I32(startu);
  471. end = I32(endu);
  472. I32 drawcallCount = 0;
  473. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  474. {
  475. const I32 faceDrawcallCount = I32(probe.m_renderQueues[faceIdx]->m_renderables.getSize());
  476. const I32 localStart = max(I32(0), start - drawcallCount);
  477. const I32 localEnd = min(faceDrawcallCount, end - drawcallCount);
  478. if(localStart < localEnd)
  479. {
  480. const U32 viewportX = faceIdx * m_tileSize;
  481. cmdb->setViewport(viewportX, 0, m_tileSize, m_tileSize);
  482. cmdb->setScissor(viewportX, 0, m_tileSize, m_tileSize);
  483. const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
  484. ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
  485. m_r->getSceneDrawer().drawRange(
  486. Pass::GB, rqueue.m_viewMatrix, rqueue.m_viewProjectionMatrix,
  487. Mat4::getIdentity(), // Don't care about prev mats since we don't care about velocity
  488. cmdb, m_r->getSamplers().m_trilinearRepeat, rqueue.m_renderables.getBegin() + localStart,
  489. rqueue.m_renderables.getBegin() + localEnd, MAX_LOD_COUNT - 1, MAX_LOD_COUNT - 1);
  490. }
  491. drawcallCount += faceDrawcallCount;
  492. }
  493. ANKI_ASSERT(giCtx.m_gbufferDrawcallCount == U32(drawcallCount));
  494. // It's secondary, no need to restore the state
  495. }
  496. void IndirectDiffuseProbes::runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
  497. {
  498. ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
  499. ANKI_TRACE_SCOPED_EVENT(R_GI);
  500. const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
  501. I32 start, end;
  502. U32 startu, endu;
  503. splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex, rgraphCtx.m_secondLevelCommandBufferCount,
  504. giCtx.m_smDrawcallCount, startu, endu);
  505. start = I32(startu);
  506. end = I32(endu);
  507. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  508. cmdb->setPolygonOffset(1.0f, 1.0f);
  509. I32 drawcallCount = 0;
  510. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  511. {
  512. ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
  513. const RenderQueue& faceRenderQueue = *probe.m_renderQueues[faceIdx];
  514. ANKI_ASSERT(faceRenderQueue.m_directionalLight.hasShadow());
  515. ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0]);
  516. const RenderQueue& cascadeRenderQueue = *faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0];
  517. const I32 faceDrawcallCount = I32(cascadeRenderQueue.m_renderables.getSize());
  518. const I32 localStart = max(I32(0), start - drawcallCount);
  519. const I32 localEnd = min(faceDrawcallCount, end - drawcallCount);
  520. if(localStart < localEnd)
  521. {
  522. const U32 rez = m_shadowMapping.m_rtDescr.m_height;
  523. cmdb->setViewport(rez * faceIdx, 0, rez, rez);
  524. cmdb->setScissor(rez * faceIdx, 0, rez, rez);
  525. ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
  526. m_r->getSceneDrawer().drawRange(
  527. Pass::SM, cascadeRenderQueue.m_viewMatrix, cascadeRenderQueue.m_viewProjectionMatrix,
  528. Mat4::getIdentity(), // Don't care about prev matrices here
  529. cmdb, m_r->getSamplers().m_trilinearRepeatAniso,
  530. cascadeRenderQueue.m_renderables.getBegin() + localStart,
  531. cascadeRenderQueue.m_renderables.getBegin() + localEnd, MAX_LOD_COUNT - 1, MAX_LOD_COUNT - 1);
  532. }
  533. }
  534. // It's secondary, no need to restore the state
  535. }
  536. void IndirectDiffuseProbes::runLightShading(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
  537. {
  538. ANKI_TRACE_SCOPED_EVENT(R_GI);
  539. ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
  540. const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
  541. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  542. // Set common state for all lights
  543. {
  544. // NOTE: Use nearest sampler because we don't want the result to sample the near tiles
  545. cmdb->bindSampler(0, 2, m_r->getSamplers().m_nearestNearestClamp);
  546. rgraphCtx.bindColorTexture(0, 3, giCtx.m_gbufferColorRts[0]);
  547. rgraphCtx.bindColorTexture(0, 4, giCtx.m_gbufferColorRts[1]);
  548. rgraphCtx.bindColorTexture(0, 5, giCtx.m_gbufferColorRts[2]);
  549. rgraphCtx.bindTexture(0, 6, giCtx.m_gbufferDepthRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
  550. // Get shadowmap info
  551. if(probe.m_renderQueues[0]->m_directionalLight.isEnabled())
  552. {
  553. ANKI_ASSERT(giCtx.m_shadowsRt.isValid());
  554. cmdb->bindSampler(0, 7, m_shadowMapping.m_shadowSampler);
  555. rgraphCtx.bindTexture(0, 8, giCtx.m_shadowsRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
  556. }
  557. }
  558. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  559. {
  560. ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
  561. const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
  562. const U32 rez = m_tileSize;
  563. cmdb->setScissor(rez * faceIdx, 0, rez, rez);
  564. cmdb->setViewport(rez * faceIdx, 0, rez, rez);
  565. TraditionalDeferredLightShadingDrawInfo dsInfo;
  566. dsInfo.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
  567. dsInfo.m_invViewProjectionMatrix = rqueue.m_viewProjectionMatrix.getInverse();
  568. dsInfo.m_cameraPosWSpace = rqueue.m_cameraTransform.getTranslationPart();
  569. dsInfo.m_viewport = UVec4(faceIdx * m_tileSize, 0, m_tileSize, m_tileSize);
  570. dsInfo.m_gbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize * 6), 1.0f / F32(m_tileSize));
  571. dsInfo.m_gbufferTexCoordsBias = Vec2(0.0f, 0.0f);
  572. dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
  573. dsInfo.m_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
  574. dsInfo.m_cameraNear = probe.m_renderQueues[faceIdx]->m_cameraNear;
  575. dsInfo.m_cameraFar = probe.m_renderQueues[faceIdx]->m_cameraFar;
  576. dsInfo.m_directionalLight = (probe.m_renderQueues[faceIdx]->m_directionalLight.isEnabled())
  577. ? &probe.m_renderQueues[faceIdx]->m_directionalLight
  578. : nullptr;
  579. dsInfo.m_pointLights = rqueue.m_pointLights;
  580. dsInfo.m_spotLights = rqueue.m_spotLights;
  581. dsInfo.m_commandBuffer = cmdb;
  582. m_lightShading.m_deferred.drawLights(dsInfo);
  583. }
  584. }
  585. void IndirectDiffuseProbes::runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
  586. {
  587. ANKI_TRACE_SCOPED_EVENT(R_GI);
  588. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  589. ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
  590. const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
  591. const U32 probeIdx = U32(&probe - &giCtx.m_ctx->m_renderQueue->m_giProbes.getFront());
  592. cmdb->bindShaderProgram(m_irradiance.m_grProg);
  593. // Bind resources
  594. cmdb->bindSampler(0, 0, m_r->getSamplers().m_nearestNearestClamp);
  595. rgraphCtx.bindColorTexture(0, 1, giCtx.m_lightShadingRt);
  596. for(U32 i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT - 1; ++i)
  597. {
  598. rgraphCtx.bindColorTexture(0, 2, giCtx.m_gbufferColorRts[i], i);
  599. }
  600. // Bind temporary memory
  601. allocateAndBindStorage<void*>(sizeof(Vec4) * 6 * m_tileSize * m_tileSize, cmdb, 0, 3);
  602. rgraphCtx.bindImage(0, 4, giCtx.m_irradianceProbeRts[probeIdx], TextureSubresourceInfo());
  603. struct
  604. {
  605. IVec3 m_volumeTexel;
  606. I32 m_nextTexelOffsetInU;
  607. } unis;
  608. unis.m_volumeTexel = IVec3(giCtx.m_cellOfTheProbeToUpdateThisFrame.x(), giCtx.m_cellOfTheProbeToUpdateThisFrame.y(),
  609. giCtx.m_cellOfTheProbeToUpdateThisFrame.z());
  610. unis.m_nextTexelOffsetInU = probe.m_cellCounts.x();
  611. cmdb->setPushConstants(&unis, sizeof(unis));
  612. // Dispatch
  613. cmdb->dispatchCompute(1, 1, 1);
  614. }
  615. } // end namespace anki