ProbeReflections.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/ProbeReflections.h>
  6. #include <AnKi/Renderer/LightShading.h>
  7. #include <AnKi/Renderer/FinalComposite.h>
  8. #include <AnKi/Renderer/GBuffer.h>
  9. #include <AnKi/Renderer/RenderQueue.h>
  10. #include <AnKi/Core/ConfigSet.h>
  11. #include <AnKi/Util/Tracer.h>
  12. #include <AnKi/Resource/MeshResource.h>
  13. #include <AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h>
  14. namespace anki
  15. {
  16. ProbeReflections::ProbeReflections(Renderer* r)
  17. : RendererObject(r)
  18. , m_lightShading(r)
  19. {
  20. }
  21. ProbeReflections::~ProbeReflections()
  22. {
  23. m_cacheEntries.destroy(getAllocator());
  24. m_probeUuidToCacheEntryIdx.destroy(getAllocator());
  25. }
  26. Error ProbeReflections::init(const ConfigSet& config)
  27. {
  28. ANKI_R_LOGI("Initializing image reflections");
  29. const Error err = initInternal(config);
  30. if(err)
  31. {
  32. ANKI_R_LOGE("Failed to initialize image reflections");
  33. }
  34. return err;
  35. }
  36. Error ProbeReflections::initInternal(const ConfigSet& config)
  37. {
  38. // Init cache entries
  39. m_cacheEntries.create(getAllocator(), config.getNumberU32("r_probeRefectionlMaxSimultaneousProbeCount"));
  40. ANKI_CHECK(initGBuffer(config));
  41. ANKI_CHECK(initLightShading(config));
  42. ANKI_CHECK(initIrradiance(config));
  43. ANKI_CHECK(initIrradianceToRefl(config));
  44. ANKI_CHECK(initShadowMapping(config));
  45. // Load split sum integration LUT
  46. ANKI_CHECK(getResourceManager().loadResource("EngineAssets/SplitSumIntegration.png", m_integrationLut));
  47. SamplerInitInfo sinit;
  48. sinit.m_minMagFilter = SamplingFilter::LINEAR;
  49. sinit.m_mipmapFilter = SamplingFilter::BASE;
  50. sinit.m_minLod = 0.0;
  51. sinit.m_maxLod = 1.0;
  52. sinit.m_addressing = SamplingAddressing::CLAMP;
  53. m_integrationLutSampler = getGrManager().newSampler(sinit);
  54. return Error::NONE;
  55. }
  56. Error ProbeReflections::initGBuffer(const ConfigSet& config)
  57. {
  58. m_gbuffer.m_tileSize = config.getNumberU32("r_probeReflectionResolution");
  59. // Create RT descriptions
  60. {
  61. RenderTargetDescription texinit =
  62. m_r->create2DRenderTargetDescription(m_gbuffer.m_tileSize * 6, m_gbuffer.m_tileSize,
  63. GBUFFER_COLOR_ATTACHMENT_PIXEL_FORMATS[0], "CubeRefl GBuffer");
  64. // Create color RT descriptions
  65. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  66. {
  67. texinit.m_format = GBUFFER_COLOR_ATTACHMENT_PIXEL_FORMATS[i];
  68. m_gbuffer.m_colorRtDescrs[i] = texinit;
  69. m_gbuffer.m_colorRtDescrs[i].setName(
  70. StringAuto(getAllocator()).sprintf("CubeRefl GBuff Col #%u", i).toCString());
  71. m_gbuffer.m_colorRtDescrs[i].bake();
  72. }
  73. // Create depth RT
  74. texinit.m_format = GBUFFER_DEPTH_ATTACHMENT_PIXEL_FORMAT;
  75. texinit.setName("CubeRefl GBuff Depth");
  76. m_gbuffer.m_depthRtDescr = texinit;
  77. m_gbuffer.m_depthRtDescr.bake();
  78. }
  79. // Create FB descr
  80. {
  81. m_gbuffer.m_fbDescr.m_colorAttachmentCount = GBUFFER_COLOR_ATTACHMENT_COUNT;
  82. for(U j = 0; j < GBUFFER_COLOR_ATTACHMENT_COUNT; ++j)
  83. {
  84. m_gbuffer.m_fbDescr.m_colorAttachments[j].m_loadOperation = AttachmentLoadOperation::CLEAR;
  85. }
  86. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  87. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  88. m_gbuffer.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
  89. m_gbuffer.m_fbDescr.bake();
  90. }
  91. return Error::NONE;
  92. }
  93. Error ProbeReflections::initLightShading(const ConfigSet& config)
  94. {
  95. m_lightShading.m_tileSize = config.getNumberU32("r_probeReflectionResolution");
  96. m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
  97. // Init cube arr
  98. {
  99. TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(
  100. m_lightShading.m_tileSize, m_lightShading.m_tileSize, LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT,
  101. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_COMPUTE | TextureUsageBit::IMAGE_COMPUTE_READ
  102. | TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::ALL_FRAMEBUFFER_ATTACHMENT
  103. | TextureUsageBit::GENERATE_MIPMAPS,
  104. "CubeRefl refl");
  105. texinit.m_mipmapCount = U8(m_lightShading.m_mipCount);
  106. texinit.m_type = TextureType::CUBE_ARRAY;
  107. texinit.m_layerCount = m_cacheEntries.getSize();
  108. texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
  109. m_lightShading.m_cubeArr = m_r->createAndClearRenderTarget(texinit);
  110. }
  111. // Init deferred
  112. ANKI_CHECK(m_lightShading.m_deferred.init());
  113. return Error::NONE;
  114. }
  115. Error ProbeReflections::initIrradiance(const ConfigSet& config)
  116. {
  117. m_irradiance.m_workgroupSize = config.getNumberU32("r_probeReflectionIrradianceResolution");
  118. // Create prog
  119. {
  120. ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/IrradianceDice.ankiprog", m_irradiance.m_prog));
  121. ShaderProgramResourceVariantInitInfo variantInitInfo(m_irradiance.m_prog);
  122. variantInitInfo.addMutation("WORKGROUP_SIZE_XY", U32(m_irradiance.m_workgroupSize));
  123. variantInitInfo.addMutation("LIGHT_SHADING_TEX", 1);
  124. variantInitInfo.addMutation("STORE_LOCATION", 1);
  125. variantInitInfo.addMutation("SECOND_BOUNCE", 0);
  126. const ShaderProgramResourceVariant* variant;
  127. m_irradiance.m_prog->getOrCreateVariant(variantInitInfo, variant);
  128. m_irradiance.m_grProg = variant->getProgram();
  129. }
  130. // Create buff
  131. {
  132. BufferInitInfo init;
  133. init.m_usage = BufferUsageBit::ALL_STORAGE;
  134. init.m_size = 6 * sizeof(Vec4);
  135. m_irradiance.m_diceValuesBuff = getGrManager().newBuffer(init);
  136. }
  137. return Error::NONE;
  138. }
  139. Error ProbeReflections::initIrradianceToRefl(const ConfigSet& cfg)
  140. {
  141. // Create program
  142. ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/ApplyIrradianceToReflection.ankiprog",
  143. m_irradianceToRefl.m_prog));
  144. const ShaderProgramResourceVariant* variant;
  145. m_irradianceToRefl.m_prog->getOrCreateVariant(ShaderProgramResourceVariantInitInfo(m_irradianceToRefl.m_prog),
  146. variant);
  147. m_irradianceToRefl.m_grProg = variant->getProgram();
  148. return Error::NONE;
  149. }
  150. Error ProbeReflections::initShadowMapping(const ConfigSet& cfg)
  151. {
  152. const U32 resolution = cfg.getNumberU32("r_probeReflectionShadowMapResolution");
  153. ANKI_ASSERT(resolution > 8);
  154. // RT descr
  155. m_shadowMapping.m_rtDescr =
  156. m_r->create2DRenderTargetDescription(resolution * 6, resolution, Format::D32_SFLOAT, "CubeRefl SM");
  157. m_shadowMapping.m_rtDescr.bake();
  158. // FB descr
  159. m_shadowMapping.m_fbDescr.m_colorAttachmentCount = 0;
  160. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  161. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
  162. m_shadowMapping.m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  163. m_shadowMapping.m_fbDescr.bake();
  164. // Shadow sampler
  165. {
  166. SamplerInitInfo inf;
  167. inf.m_compareOperation = CompareOperation::LESS_EQUAL;
  168. inf.m_addressing = SamplingAddressing::CLAMP;
  169. inf.m_mipmapFilter = SamplingFilter::BASE;
  170. inf.m_minMagFilter = SamplingFilter::LINEAR;
  171. m_shadowMapping.m_shadowSampler = getGrManager().newSampler(inf);
  172. }
  173. return Error::NONE;
  174. }
  175. void ProbeReflections::initCacheEntry(U32 cacheEntryIdx)
  176. {
  177. CacheEntry& cacheEntry = m_cacheEntries[cacheEntryIdx];
  178. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  179. {
  180. // Light pass FB
  181. FramebufferDescription& fbDescr = cacheEntry.m_lightShadingFbDescrs[faceIdx];
  182. ANKI_ASSERT(!fbDescr.isBacked());
  183. fbDescr.m_colorAttachmentCount = 1;
  184. fbDescr.m_colorAttachments[0].m_surface.m_layer = cacheEntryIdx;
  185. fbDescr.m_colorAttachments[0].m_surface.m_face = faceIdx;
  186. fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
  187. fbDescr.bake();
  188. }
  189. }
  190. void ProbeReflections::prepareProbes(RenderingContext& ctx, ReflectionProbeQueueElement*& probeToUpdateThisFrame,
  191. U32& probeToUpdateThisFrameCacheEntryIdx)
  192. {
  193. probeToUpdateThisFrame = nullptr;
  194. probeToUpdateThisFrameCacheEntryIdx = MAX_U32;
  195. if(ANKI_UNLIKELY(ctx.m_renderQueue->m_reflectionProbes.getSize() == 0))
  196. {
  197. return;
  198. }
  199. // Iterate the probes and:
  200. // - Find a probe to update this frame
  201. // - Find a probe to update next frame
  202. // - Find the cache entries for each probe
  203. DynamicArray<ReflectionProbeQueueElement> newListOfProbes;
  204. newListOfProbes.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_reflectionProbes.getSize());
  205. U32 newListOfProbeCount = 0;
  206. Bool foundProbeToUpdateNextFrame = false;
  207. for(U32 probeIdx = 0; probeIdx < ctx.m_renderQueue->m_reflectionProbes.getSize(); ++probeIdx)
  208. {
  209. ReflectionProbeQueueElement& probe = ctx.m_renderQueue->m_reflectionProbes[probeIdx];
  210. // Find cache entry
  211. const U32 cacheEntryIdx = findBestCacheEntry(probe.m_uuid, m_r->getGlobalTimestamp(), m_cacheEntries,
  212. m_probeUuidToCacheEntryIdx, getAllocator());
  213. if(ANKI_UNLIKELY(cacheEntryIdx == MAX_U32))
  214. {
  215. // Failed
  216. ANKI_R_LOGW("There is not enough space in the indirect lighting atlas for more probes. "
  217. "Increase the r_probeRefectionlMaxSimultaneousProbeCount or decrease the scene's probes");
  218. continue;
  219. }
  220. const Bool probeFoundInCache = m_cacheEntries[cacheEntryIdx].m_uuid == probe.m_uuid;
  221. // Check if we _should_ and _can_ update the probe
  222. const Bool needsUpdate = !probeFoundInCache;
  223. if(ANKI_UNLIKELY(needsUpdate))
  224. {
  225. const Bool canUpdateThisFrame = probeToUpdateThisFrame == nullptr && probe.m_renderQueues[0] != nullptr;
  226. const Bool canUpdateNextFrame = !foundProbeToUpdateNextFrame;
  227. if(!canUpdateThisFrame && canUpdateNextFrame)
  228. {
  229. // Probe will be updated next frame
  230. foundProbeToUpdateNextFrame = true;
  231. probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData);
  232. continue;
  233. }
  234. else if(!canUpdateThisFrame)
  235. {
  236. // Can't be updated this frame so remove it from the list
  237. continue;
  238. }
  239. else
  240. {
  241. // Can be updated this frame so continue with it
  242. probeToUpdateThisFrameCacheEntryIdx = cacheEntryIdx;
  243. probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
  244. }
  245. }
  246. // All good, can use this probe in this frame
  247. // Update the cache entry
  248. m_cacheEntries[cacheEntryIdx].m_uuid = probe.m_uuid;
  249. m_cacheEntries[cacheEntryIdx].m_lastUsedTimestamp = m_r->getGlobalTimestamp();
  250. // Update the probe
  251. probe.m_textureArrayIndex = cacheEntryIdx;
  252. // Push the probe to the new list
  253. newListOfProbes[newListOfProbeCount++] = probe;
  254. // Update cache map
  255. if(!probeFoundInCache)
  256. {
  257. m_probeUuidToCacheEntryIdx.emplace(getAllocator(), probe.m_uuid, cacheEntryIdx);
  258. }
  259. // Don't gather renderables next frame
  260. if(probe.m_renderQueues[0] != nullptr)
  261. {
  262. probe.m_feedbackCallback(false, probe.m_feedbackCallbackUserData);
  263. }
  264. }
  265. // Replace the probe list in the queue
  266. if(newListOfProbeCount > 0)
  267. {
  268. ReflectionProbeQueueElement* firstProbe;
  269. U32 probeCount, storage;
  270. newListOfProbes.moveAndReset(firstProbe, probeCount, storage);
  271. ctx.m_renderQueue->m_reflectionProbes = WeakArray<ReflectionProbeQueueElement>(firstProbe, newListOfProbeCount);
  272. }
  273. else
  274. {
  275. ctx.m_renderQueue->m_reflectionProbes = WeakArray<ReflectionProbeQueueElement>();
  276. newListOfProbes.destroy(ctx.m_tempAllocator);
  277. }
  278. }
  279. void ProbeReflections::runGBuffer(RenderPassWorkContext& rgraphCtx)
  280. {
  281. ANKI_ASSERT(m_ctx.m_probe);
  282. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  283. const ReflectionProbeQueueElement& probe = *m_ctx.m_probe;
  284. const CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  285. I32 start, end;
  286. U32 startu, endu;
  287. splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex, rgraphCtx.m_secondLevelCommandBufferCount,
  288. m_ctx.m_gbufferRenderableCount, startu, endu);
  289. start = I32(startu);
  290. end = I32(endu);
  291. I32 drawcallCount = 0;
  292. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  293. {
  294. const I32 faceDrawcallCount = I32(probe.m_renderQueues[faceIdx]->m_renderables.getSize());
  295. const I32 localStart = max(I32(0), start - drawcallCount);
  296. const I32 localEnd = min(faceDrawcallCount, end - drawcallCount);
  297. if(localStart < localEnd)
  298. {
  299. const U32 viewportX = faceIdx * m_gbuffer.m_tileSize;
  300. cmdb->setViewport(viewportX, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
  301. cmdb->setScissor(viewportX, 0, m_gbuffer.m_tileSize, m_gbuffer.m_tileSize);
  302. const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
  303. ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
  304. m_r->getSceneDrawer().drawRange(
  305. Pass::GB, rqueue.m_viewMatrix, rqueue.m_viewProjectionMatrix,
  306. Mat4::getIdentity(), // Don't care about prev mats
  307. cmdb, m_r->getSamplers().m_trilinearRepeat, rqueue.m_renderables.getBegin() + localStart,
  308. rqueue.m_renderables.getBegin() + localEnd, MAX_LOD_COUNT - 1, MAX_LOD_COUNT - 1);
  309. }
  310. }
  311. // Restore state
  312. cmdb->setScissor(0, 0, MAX_U32, MAX_U32);
  313. }
  314. void ProbeReflections::runLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
  315. {
  316. ANKI_ASSERT(faceIdx <= 6);
  317. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  318. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  319. ANKI_ASSERT(m_ctx.m_probe);
  320. const ReflectionProbeQueueElement& probe = *m_ctx.m_probe;
  321. const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
  322. // Set common state for all lights
  323. // NOTE: Use nearest sampler because we don't want the result to sample the near tiles
  324. cmdb->bindSampler(0, 2, m_r->getSamplers().m_nearestNearestClamp);
  325. rgraphCtx.bindColorTexture(0, 3, m_ctx.m_gbufferColorRts[0]);
  326. rgraphCtx.bindColorTexture(0, 4, m_ctx.m_gbufferColorRts[1]);
  327. rgraphCtx.bindColorTexture(0, 5, m_ctx.m_gbufferColorRts[2]);
  328. rgraphCtx.bindTexture(0, 6, m_ctx.m_gbufferDepthRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
  329. // Get shadowmap info
  330. const Bool hasDirLight = probe.m_renderQueues[0]->m_directionalLight.m_uuid;
  331. if(hasDirLight)
  332. {
  333. ANKI_ASSERT(m_ctx.m_shadowMapRt.isValid());
  334. cmdb->bindSampler(0, 7, m_shadowMapping.m_shadowSampler);
  335. rgraphCtx.bindTexture(0, 8, m_ctx.m_shadowMapRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
  336. }
  337. TraditionalDeferredLightShadingDrawInfo dsInfo;
  338. dsInfo.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
  339. dsInfo.m_invViewProjectionMatrix = rqueue.m_viewProjectionMatrix.getInverse();
  340. dsInfo.m_cameraPosWSpace = rqueue.m_cameraTransform.getTranslationPart();
  341. dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
  342. dsInfo.m_gbufferTexCoordsScale =
  343. Vec2(1.0f / F32(m_lightShading.m_tileSize * 6), 1.0f / F32(m_lightShading.m_tileSize));
  344. dsInfo.m_gbufferTexCoordsBias = Vec2(F32(faceIdx) * (1.0f / 6.0f), 0.0f);
  345. dsInfo.m_lightbufferTexCoordsScale =
  346. Vec2(1.0f / F32(m_lightShading.m_tileSize), 1.0f / F32(m_lightShading.m_tileSize));
  347. dsInfo.m_lightbufferTexCoordsBias = Vec2(0.0f, 0.0f);
  348. dsInfo.m_cameraNear = probe.m_renderQueues[faceIdx]->m_cameraNear;
  349. dsInfo.m_cameraFar = probe.m_renderQueues[faceIdx]->m_cameraFar;
  350. dsInfo.m_directionalLight = (hasDirLight) ? &probe.m_renderQueues[faceIdx]->m_directionalLight : nullptr;
  351. dsInfo.m_pointLights = rqueue.m_pointLights;
  352. dsInfo.m_spotLights = rqueue.m_spotLights;
  353. dsInfo.m_commandBuffer = cmdb;
  354. m_lightShading.m_deferred.drawLights(dsInfo);
  355. }
  356. void ProbeReflections::runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
  357. {
  358. ANKI_ASSERT(faceIdx < 6);
  359. ANKI_ASSERT(m_ctx.m_cacheEntryIdx < m_cacheEntries.getSize());
  360. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  361. TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, m_ctx.m_cacheEntryIdx));
  362. subresource.m_mipmapCount = m_lightShading.m_mipCount;
  363. TexturePtr texToBind;
  364. rgraphCtx.getRenderTargetState(m_ctx.m_lightShadingRt, subresource, texToBind);
  365. TextureViewInitInfo viewInit(texToBind, subresource);
  366. rgraphCtx.m_commandBuffer->generateMipmaps2d(getGrManager().newTextureView(viewInit));
  367. }
  368. void ProbeReflections::runIrradiance(RenderPassWorkContext& rgraphCtx)
  369. {
  370. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  371. const U32 cacheEntryIdx = m_ctx.m_cacheEntryIdx;
  372. ANKI_ASSERT(cacheEntryIdx < m_cacheEntries.getSize());
  373. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  374. cmdb->bindShaderProgram(m_irradiance.m_grProg);
  375. // Bind stuff
  376. cmdb->bindSampler(0, 0, m_r->getSamplers().m_nearestNearestClamp);
  377. TextureSubresourceInfo subresource;
  378. subresource.m_faceCount = 6;
  379. subresource.m_firstLayer = cacheEntryIdx;
  380. rgraphCtx.bindTexture(0, 1, m_ctx.m_lightShadingRt, subresource);
  381. allocateAndBindStorage<void*>(sizeof(Vec4) * 6 * m_irradiance.m_workgroupSize * m_irradiance.m_workgroupSize, cmdb,
  382. 0, 3);
  383. cmdb->bindStorageBuffer(0, 4, m_irradiance.m_diceValuesBuff, 0, m_irradiance.m_diceValuesBuff->getSize());
  384. // Draw
  385. cmdb->dispatchCompute(1, 1, 1);
  386. }
  387. void ProbeReflections::runIrradianceToRefl(RenderPassWorkContext& rgraphCtx)
  388. {
  389. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  390. const U32 cacheEntryIdx = m_ctx.m_cacheEntryIdx;
  391. ANKI_ASSERT(cacheEntryIdx < m_cacheEntries.getSize());
  392. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  393. cmdb->bindShaderProgram(m_irradianceToRefl.m_grProg);
  394. // Bind resources
  395. cmdb->bindSampler(0, 0, m_r->getSamplers().m_nearestNearestClamp);
  396. rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[0], 0);
  397. rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[1], 1);
  398. rgraphCtx.bindColorTexture(0, 1, m_ctx.m_gbufferColorRts[2], 2);
  399. cmdb->bindStorageBuffer(0, 2, m_irradiance.m_diceValuesBuff, 0, m_irradiance.m_diceValuesBuff->getSize());
  400. TextureSubresourceInfo subresource;
  401. subresource.m_faceCount = 6;
  402. subresource.m_firstLayer = cacheEntryIdx;
  403. rgraphCtx.bindImage(0, 3, m_ctx.m_lightShadingRt, subresource);
  404. dispatchPPCompute(cmdb, 8, 8, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
  405. }
  406. void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
  407. {
  408. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  409. #if ANKI_EXTRA_CHECKS
  410. m_ctx = {};
  411. #endif
  412. RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
  413. // Prepare the probes and maybe get one to render this frame
  414. ReflectionProbeQueueElement* probeToUpdate;
  415. U32 probeToUpdateCacheEntryIdx;
  416. prepareProbes(rctx, probeToUpdate, probeToUpdateCacheEntryIdx);
  417. // Render a probe if needed
  418. if(!probeToUpdate)
  419. {
  420. // Just import and exit
  421. m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
  422. return;
  423. }
  424. m_ctx.m_cacheEntryIdx = probeToUpdateCacheEntryIdx;
  425. m_ctx.m_probe = probeToUpdate;
  426. if(!m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[0].isBacked())
  427. {
  428. initCacheEntry(probeToUpdateCacheEntryIdx);
  429. }
  430. // G-buffer pass
  431. {
  432. // RTs
  433. Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS> rts;
  434. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  435. {
  436. m_ctx.m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
  437. rts[i] = m_ctx.m_gbufferColorRts[i];
  438. }
  439. m_ctx.m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
  440. // Compute task count
  441. m_ctx.m_gbufferRenderableCount = 0;
  442. for(U32 i = 0; i < 6; ++i)
  443. {
  444. m_ctx.m_gbufferRenderableCount += probeToUpdate->m_renderQueues[i]->m_renderables.getSize();
  445. }
  446. const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_gbufferRenderableCount);
  447. // Pass
  448. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("CubeRefl gbuff");
  449. pass.setFramebufferInfo(m_gbuffer.m_fbDescr, rts, m_ctx.m_gbufferDepthRt);
  450. pass.setWork(taskCount, [this](RenderPassWorkContext& rgraphCtx) { runGBuffer(rgraphCtx); });
  451. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  452. {
  453. pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  454. }
  455. TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
  456. pass.newDependency({m_ctx.m_gbufferDepthRt, TextureUsageBit::ALL_FRAMEBUFFER_ATTACHMENT, subresource});
  457. }
  458. // Shadow pass. Optional
  459. if(probeToUpdate->m_renderQueues[0]->m_directionalLight.m_uuid
  460. && probeToUpdate->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
  461. {
  462. // Update light matrices
  463. for(U i = 0; i < 6; ++i)
  464. {
  465. ANKI_ASSERT(probeToUpdate->m_renderQueues[i]->m_directionalLight.m_uuid
  466. && probeToUpdate->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
  467. const F32 xScale = 1.0f / 6.0f;
  468. const F32 yScale = 1.0f;
  469. const F32 xOffset = F32(i) * (1.0f / 6.0f);
  470. const F32 yOffset = 0.0f;
  471. 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,
  472. 0.0f, 0.0f, 1.0f);
  473. Mat4& lightMat = probeToUpdate->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
  474. lightMat = atlasMtx * lightMat;
  475. }
  476. // Compute task count
  477. m_ctx.m_shadowRenderableCount = 0;
  478. for(U32 i = 0; i < 6; ++i)
  479. {
  480. m_ctx.m_shadowRenderableCount +=
  481. probeToUpdate->m_renderQueues[i]->m_directionalLight.m_shadowRenderQueues[0]->m_renderables.getSize();
  482. }
  483. const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_shadowRenderableCount);
  484. // RT
  485. m_ctx.m_shadowMapRt = rgraph.newRenderTarget(m_shadowMapping.m_rtDescr);
  486. // Pass
  487. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("CubeRefl SM");
  488. pass.setFramebufferInfo(m_shadowMapping.m_fbDescr, {}, m_ctx.m_shadowMapRt);
  489. pass.setWork(taskCount, [this](RenderPassWorkContext& rgraphCtx) { runShadowMapping(rgraphCtx); });
  490. TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
  491. pass.newDependency({m_ctx.m_shadowMapRt, TextureUsageBit::ALL_FRAMEBUFFER_ATTACHMENT, subresource});
  492. }
  493. else
  494. {
  495. m_ctx.m_shadowMapRt = {};
  496. }
  497. // Light shading passes
  498. {
  499. // RT
  500. m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
  501. // Passes
  502. static const Array<CString, 6> passNames = {"CubeRefl LightShad #0", "CubeRefl LightShad #1",
  503. "CubeRefl LightShad #2", "CubeRefl LightShad #3",
  504. "CubeRefl LightShad #4", "CubeRefl LightShad #5"};
  505. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  506. {
  507. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
  508. pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[faceIdx],
  509. {{m_ctx.m_lightShadingRt}}, {});
  510. pass.setWork([this, faceIdx](RenderPassWorkContext& rgraphCtx) { runLightShading(faceIdx, rgraphCtx); });
  511. TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
  512. pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, subresource});
  513. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
  514. {
  515. pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
  516. }
  517. pass.newDependency({m_ctx.m_gbufferDepthRt, TextureUsageBit::SAMPLED_FRAGMENT,
  518. TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
  519. if(m_ctx.m_shadowMapRt.isValid())
  520. {
  521. pass.newDependency({m_ctx.m_shadowMapRt, TextureUsageBit::SAMPLED_FRAGMENT});
  522. }
  523. }
  524. }
  525. // Irradiance passes
  526. {
  527. m_ctx.m_irradianceDiceValuesBuffHandle =
  528. rgraph.importBuffer(m_irradiance.m_diceValuesBuff, BufferUsageBit::NONE);
  529. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("CubeRefl Irradiance");
  530. pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runIrradiance(rgraphCtx); });
  531. // Read a cube but only one layer and level
  532. TextureSubresourceInfo readSubresource;
  533. readSubresource.m_faceCount = 6;
  534. readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
  535. pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_COMPUTE, readSubresource});
  536. pass.newDependency({m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::STORAGE_COMPUTE_WRITE});
  537. }
  538. // Write irradiance back to refl
  539. {
  540. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("CubeRefl apply indirect");
  541. pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runIrradianceToRefl(rgraphCtx); });
  542. for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT - 1; ++i)
  543. {
  544. pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_COMPUTE});
  545. }
  546. TextureSubresourceInfo subresource;
  547. subresource.m_faceCount = 6;
  548. subresource.m_firstLayer = probeToUpdateCacheEntryIdx;
  549. pass.newDependency({m_ctx.m_lightShadingRt,
  550. TextureUsageBit::IMAGE_COMPUTE_READ | TextureUsageBit::IMAGE_COMPUTE_WRITE, subresource});
  551. pass.newDependency({m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::STORAGE_COMPUTE_READ});
  552. }
  553. // Mipmapping "passes"
  554. {
  555. static const Array<CString, 6> passNames = {"CubeRefl Mip #0", "CubeRefl Mip #1", "CubeRefl Mip #2",
  556. "CubeRefl Mip #3", "CubeRefl Mip #4", "CubeRefl Mip #5"};
  557. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  558. {
  559. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
  560. pass.setWork(
  561. [this, faceIdx](RenderPassWorkContext& rgraphCtx) { runMipmappingOfLightShading(faceIdx, rgraphCtx); });
  562. TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
  563. subresource.m_mipmapCount = m_lightShading.m_mipCount;
  564. pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
  565. }
  566. }
  567. }
  568. void ProbeReflections::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  569. {
  570. ANKI_ASSERT(m_ctx.m_probe);
  571. ANKI_TRACE_SCOPED_EVENT(R_CUBE_REFL);
  572. I32 start, end;
  573. U32 startu, endu;
  574. splitThreadedProblem(rgraphCtx.m_currentSecondLevelCommandBufferIndex, rgraphCtx.m_secondLevelCommandBufferCount,
  575. m_ctx.m_shadowRenderableCount, startu, endu);
  576. start = I32(startu);
  577. end = I32(endu);
  578. const CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  579. cmdb->setPolygonOffset(1.0f, 1.0f);
  580. I32 drawcallCount = 0;
  581. for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
  582. {
  583. ANKI_ASSERT(m_ctx.m_probe->m_renderQueues[faceIdx]);
  584. const RenderQueue& faceRenderQueue = *m_ctx.m_probe->m_renderQueues[faceIdx];
  585. ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_uuid != 0);
  586. ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowCascadeCount == 1);
  587. ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0]);
  588. const RenderQueue& cascadeRenderQueue = *faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0];
  589. const I32 faceDrawcallCount = I32(cascadeRenderQueue.m_renderables.getSize());
  590. const I32 localStart = max(I32(0), start - drawcallCount);
  591. const I32 localEnd = min(faceDrawcallCount, end - drawcallCount);
  592. if(localStart < localEnd)
  593. {
  594. const U32 rez = m_shadowMapping.m_rtDescr.m_height;
  595. cmdb->setViewport(rez * faceIdx, 0, rez, rez);
  596. cmdb->setScissor(rez * faceIdx, 0, rez, rez);
  597. ANKI_ASSERT(localStart >= 0 && localEnd <= faceDrawcallCount);
  598. m_r->getSceneDrawer().drawRange(
  599. Pass::SM, cascadeRenderQueue.m_viewMatrix, cascadeRenderQueue.m_viewProjectionMatrix,
  600. Mat4::getIdentity(), // Don't care about prev matrices here
  601. cmdb, m_r->getSamplers().m_trilinearRepeatAniso,
  602. cascadeRenderQueue.m_renderables.getBegin() + localStart,
  603. cascadeRenderQueue.m_renderables.getBegin() + localEnd, MAX_LOD_COUNT - 1, MAX_LOD_COUNT - 1);
  604. }
  605. }
  606. }
  607. } // end namespace anki