ShadowMapping.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. // Copyright (C) 2009-2018, 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/ShadowMapping.h>
  6. #include <anki/renderer/Renderer.h>
  7. #include <anki/renderer/RenderQueue.h>
  8. #include <anki/core/App.h>
  9. #include <anki/core/Trace.h>
  10. #include <anki/misc/ConfigSet.h>
  11. #include <anki/util/ThreadPool.h>
  12. namespace anki
  13. {
  14. struct ShadowMapping::LightToRenderToScratchInfo
  15. {
  16. Array<U32, 4> m_viewport;
  17. RenderQueue* m_renderQueue;
  18. U32 m_drawcallCount;
  19. };
  20. ShadowMapping::~ShadowMapping()
  21. {
  22. m_tiles.destroy(getAllocator());
  23. m_lightUuidToTileIdx.destroy(getAllocator());
  24. }
  25. Error ShadowMapping::init(const ConfigSet& config)
  26. {
  27. ANKI_R_LOGI("Initializing shadowmapping");
  28. Error err = initInternal(config);
  29. if(err)
  30. {
  31. ANKI_R_LOGE("Failed to initialize shadowmapping");
  32. }
  33. return err;
  34. }
  35. Error ShadowMapping::initScratch(const ConfigSet& cfg)
  36. {
  37. // Init the shadowmaps and FBs
  38. {
  39. m_scratchTileCount = cfg.getNumber("r.shadowMapping.scratchTileCount");
  40. m_scratchTileResolution = cfg.getNumber("r.shadowMapping.resolution");
  41. // RT
  42. m_scratchRtDescr = m_r->create2DRenderTargetDescription(m_scratchTileResolution * m_scratchTileCount,
  43. m_scratchTileResolution,
  44. SHADOW_DEPTH_PIXEL_FORMAT,
  45. "Scratch ShadMap");
  46. m_scratchRtDescr.bake();
  47. // FB
  48. m_scratchFbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  49. m_scratchFbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0;
  50. m_scratchFbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  51. m_scratchFbDescr.bake();
  52. }
  53. return Error::NONE;
  54. }
  55. Error ShadowMapping::initEsm(const ConfigSet& cfg)
  56. {
  57. // Init RTs and FBs
  58. {
  59. m_tileResolution = cfg.getNumber("r.shadowMapping.resolution");
  60. m_tileCountPerRowOrColumn = cfg.getNumber("r.shadowMapping.tileCountPerRowOrColumn");
  61. m_atlasResolution = m_tileResolution * m_tileCountPerRowOrColumn;
  62. // RT
  63. TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(m_atlasResolution,
  64. m_atlasResolution,
  65. SHADOW_COLOR_PIXEL_FORMAT,
  66. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
  67. "esm");
  68. texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
  69. ClearValue clearVal;
  70. clearVal.m_colorf[0] = 1.0f;
  71. m_esmAtlas = m_r->createAndClearRenderTarget(texinit, clearVal);
  72. // FB
  73. m_esmFbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::LOAD;
  74. m_esmFbDescr.m_colorAttachmentCount = 1;
  75. m_esmFbDescr.bake();
  76. }
  77. // Tiles
  78. {
  79. m_tiles.create(getAllocator(), m_tileCountPerRowOrColumn * m_tileCountPerRowOrColumn);
  80. for(U y = 0; y < m_tileCountPerRowOrColumn; ++y)
  81. {
  82. for(U x = 0; x < m_tileCountPerRowOrColumn; ++x)
  83. {
  84. const U tileIdx = y * m_tileCountPerRowOrColumn + x;
  85. Tile& tile = m_tiles[tileIdx];
  86. tile.m_uv[0] = F32(x) / m_tileCountPerRowOrColumn;
  87. tile.m_uv[1] = F32(y) / m_tileCountPerRowOrColumn;
  88. tile.m_uv[2] = 1.0f / m_tileCountPerRowOrColumn;
  89. tile.m_uv[3] = tile.m_uv[2];
  90. tile.m_viewport[0] = x * m_tileResolution;
  91. tile.m_viewport[1] = y * m_tileResolution;
  92. tile.m_viewport[2] = m_tileResolution;
  93. tile.m_viewport[3] = m_tileResolution;
  94. }
  95. }
  96. // The first tile is always pinned
  97. m_tiles[0].m_pinned = true;
  98. }
  99. // Programs and shaders
  100. {
  101. ANKI_CHECK(
  102. getResourceManager().loadResource("shaders/ExponentialShadowmappingResolve.glslp", m_esmResolveProg));
  103. ShaderProgramResourceConstantValueInitList<1> consts(m_esmResolveProg);
  104. consts.add("INPUT_TEXTURE_SIZE", UVec2(m_scratchTileCount * m_scratchTileResolution, m_scratchTileResolution));
  105. const ShaderProgramResourceVariant* variant;
  106. m_esmResolveProg->getOrCreateVariant(consts.get(), variant);
  107. m_esmResolveGrProg = variant->getProgram();
  108. }
  109. return Error::NONE;
  110. }
  111. Error ShadowMapping::initInternal(const ConfigSet& cfg)
  112. {
  113. ANKI_CHECK(initScratch(cfg));
  114. ANKI_CHECK(initEsm(cfg));
  115. return Error::NONE;
  116. }
  117. void ShadowMapping::runEsm(RenderPassWorkContext& rgraphCtx)
  118. {
  119. ANKI_ASSERT(m_esmResolveWorkItems.getSize());
  120. ANKI_TRACE_SCOPED_EVENT(R_SM);
  121. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  122. cmdb->bindShaderProgram(m_esmResolveGrProg);
  123. rgraphCtx.bindTextureAndSampler(
  124. 0, 0, m_scratchRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH), m_r->getLinearSampler());
  125. for(const EsmResolveWorkItem& workItem : m_esmResolveWorkItems)
  126. {
  127. ANKI_TRACE_INC_COUNTER(R_SHADOW_PASSES, 1);
  128. cmdb->setViewport(
  129. workItem.m_viewportOut[0], workItem.m_viewportOut[1], workItem.m_viewportOut[2], workItem.m_viewportOut[3]);
  130. cmdb->setScissor(
  131. workItem.m_viewportOut[0], workItem.m_viewportOut[1], workItem.m_viewportOut[2], workItem.m_viewportOut[3]);
  132. Vec4* unis = allocateAndBindUniforms<Vec4*>(sizeof(Vec4) * 2, cmdb, 0, 0);
  133. unis[0] = Vec4(workItem.m_cameraNear, workItem.m_cameraFar, 0.0f, 0.0f);
  134. unis[1] = workItem.m_uvIn;
  135. drawQuad(cmdb);
  136. }
  137. // Restore GR state
  138. cmdb->setScissor(0, 0, MAX_U32, MAX_U32);
  139. }
  140. void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  141. {
  142. ANKI_ASSERT(m_scratchWorkItems.getSize());
  143. ANKI_TRACE_SCOPED_EVENT(R_SM);
  144. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  145. const U threadIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
  146. for(ScratchBufferWorkItem& work : m_scratchWorkItems)
  147. {
  148. if(work.m_threadPoolTaskIdx != threadIdx)
  149. {
  150. continue;
  151. }
  152. // Set state
  153. cmdb->setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  154. cmdb->setScissor(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  155. m_r->getSceneDrawer().drawRange(Pass::SM,
  156. work.m_renderQueue->m_viewMatrix,
  157. work.m_renderQueue->m_viewProjectionMatrix,
  158. Mat4::getIdentity(), // Don't care about prev matrices here
  159. cmdb,
  160. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement,
  161. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement
  162. + work.m_renderableElementCount);
  163. }
  164. }
  165. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  166. {
  167. ANKI_TRACE_SCOPED_EVENT(R_SM);
  168. // First process the lights
  169. U32 threadCountForScratchPass = 0;
  170. processLights(ctx, threadCountForScratchPass);
  171. // Build the render graph
  172. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  173. if(m_scratchWorkItems.getSize())
  174. {
  175. // Will have to create render passes
  176. // Scratch pass
  177. {
  178. // Compute render area
  179. const U32 minx = 0, miny = 0, height = m_scratchTileResolution;
  180. const U32 width = m_scratchTileResolution * m_scratchWorkItems.getSize();
  181. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SM scratch");
  182. m_scratchRt = rgraph.newRenderTarget(m_scratchRtDescr);
  183. pass.setFramebufferInfo(m_scratchFbDescr, {}, m_scratchRt, minx, miny, width, height);
  184. ANKI_ASSERT(
  185. threadCountForScratchPass && threadCountForScratchPass <= m_r->getThreadPool().getThreadCount());
  186. pass.setWork(runShadowmappingCallback, this, threadCountForScratchPass);
  187. TextureSubresourceInfo subresource = TextureSubresourceInfo(DepthStencilAspectBit::DEPTH);
  188. pass.newConsumer({m_scratchRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
  189. pass.newProducer({m_scratchRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
  190. }
  191. // ESM pass
  192. {
  193. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("ESM");
  194. m_esmRt = rgraph.importRenderTarget(m_esmAtlas, TextureUsageBit::SAMPLED_FRAGMENT);
  195. pass.setFramebufferInfo(m_esmFbDescr, {{m_esmRt}}, {});
  196. pass.setWork(runEsmCallback, this, 0);
  197. pass.newConsumer(
  198. {m_scratchRt, TextureUsageBit::SAMPLED_FRAGMENT, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
  199. pass.newConsumer({m_esmRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  200. pass.newProducer({m_esmRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  201. }
  202. }
  203. else
  204. {
  205. // No need for shadowmapping passes, just import the ESM atlas
  206. m_esmRt = rgraph.importRenderTarget(m_esmAtlas, TextureUsageBit::SAMPLED_FRAGMENT);
  207. }
  208. }
  209. Mat4 ShadowMapping::createSpotLightTextureMatrix(const Tile& tile)
  210. {
  211. return Mat4(tile.m_uv[2],
  212. 0.0,
  213. 0.0,
  214. tile.m_uv[0],
  215. 0.0,
  216. tile.m_uv[3],
  217. 0.0,
  218. tile.m_uv[1],
  219. 0.0,
  220. 0.0,
  221. 1.0,
  222. 0.0,
  223. 0.0,
  224. 0.0,
  225. 0.0,
  226. 1.0);
  227. }
  228. void ShadowMapping::processLights(RenderingContext& ctx, U32& threadCountForScratchPass)
  229. {
  230. // Reset stuff
  231. m_freeScratchTiles = m_scratchTileCount;
  232. // Vars
  233. DynamicArrayAuto<LightToRenderToScratchInfo> lightsToRender(ctx.m_tempAllocator);
  234. U32 drawcallCount = 0;
  235. DynamicArrayAuto<EsmResolveWorkItem> esmWorkItems(ctx.m_tempAllocator);
  236. // Process the point lights first.
  237. for(PointLightQueueElement* light : ctx.m_renderQueue->m_shadowPointLights)
  238. {
  239. // Prepare data to allocate tiles and allocate
  240. Array<U32, 6> tiles;
  241. Array<U32, 6> scratchTiles;
  242. Array<U64, 6> timestamps;
  243. Array<U32, 6> faceIndices;
  244. Array<U32, 6> drawcallCounts;
  245. U numOfFacesThatHaveDrawcalls = 0;
  246. for(U face = 0; face < 6; ++face)
  247. {
  248. ANKI_ASSERT(light->m_shadowRenderQueues[face]);
  249. if(light->m_shadowRenderQueues[face]->m_renderables.getSize())
  250. {
  251. // Has renderables, need to allocate tiles for it so add it to the arrays
  252. faceIndices[numOfFacesThatHaveDrawcalls] = face;
  253. timestamps[numOfFacesThatHaveDrawcalls] =
  254. light->m_shadowRenderQueues[face]->m_shadowRenderablesLastUpdateTimestamp;
  255. drawcallCounts[numOfFacesThatHaveDrawcalls] =
  256. light->m_shadowRenderQueues[face]->m_renderables.getSize();
  257. ++numOfFacesThatHaveDrawcalls;
  258. }
  259. }
  260. const Bool allocationFailed = numOfFacesThatHaveDrawcalls == 0
  261. || allocateTilesAndScratchTiles(light->m_uuid,
  262. numOfFacesThatHaveDrawcalls,
  263. &timestamps[0],
  264. &faceIndices[0],
  265. &drawcallCounts[0],
  266. &tiles[0],
  267. &scratchTiles[0]);
  268. if(!allocationFailed)
  269. {
  270. // All good, update the lights
  271. light->m_atlasTiles = UVec2(0u);
  272. light->m_atlasTileSize = 1.0f / m_tileCountPerRowOrColumn;
  273. numOfFacesThatHaveDrawcalls = 0;
  274. for(U face = 0; face < 6; ++face)
  275. {
  276. if(light->m_shadowRenderQueues[face]->m_renderables.getSize())
  277. {
  278. // Has drawcalls, asigned it to a tile
  279. const U32 tileIdx = tiles[numOfFacesThatHaveDrawcalls];
  280. const U32 tileIdxX = tileIdx % m_tileCountPerRowOrColumn;
  281. const U32 tileIdxY = tileIdx / m_tileCountPerRowOrColumn;
  282. ANKI_ASSERT(tileIdxX <= 31u && tileIdxY <= 31u);
  283. light->m_atlasTiles.x() |= tileIdxX << (5u * face);
  284. light->m_atlasTiles.y() |= tileIdxY << (5u * face);
  285. if(scratchTiles[numOfFacesThatHaveDrawcalls] != MAX_U32)
  286. {
  287. newScratchAndEsmResloveRenderWorkItems(tiles[numOfFacesThatHaveDrawcalls],
  288. scratchTiles[numOfFacesThatHaveDrawcalls],
  289. light->m_shadowRenderQueues[face],
  290. lightsToRender,
  291. esmWorkItems,
  292. drawcallCount);
  293. }
  294. ++numOfFacesThatHaveDrawcalls;
  295. }
  296. else
  297. {
  298. // Doesn't have renderables, point the face to the 1st tile (that is pinned)
  299. light->m_atlasTiles.x() |= 0u << (5u * face);
  300. light->m_atlasTiles.y() |= 0u << (5u * face);
  301. }
  302. }
  303. }
  304. else
  305. {
  306. // Light can't be a caster this frame
  307. memset(&light->m_shadowRenderQueues[0], 0, sizeof(light->m_shadowRenderQueues));
  308. }
  309. }
  310. // Process the spot lights
  311. for(SpotLightQueueElement* light : ctx.m_renderQueue->m_shadowSpotLights)
  312. {
  313. ANKI_ASSERT(light->m_shadowRenderQueue);
  314. // Allocate tiles
  315. U32 tileIdx, scratchTileIdx, faceIdx = 0;
  316. const U32 localDrawcallCount = light->m_shadowRenderQueue->m_renderables.getSize();
  317. const Bool allocationFailed = localDrawcallCount == 0
  318. || allocateTilesAndScratchTiles(light->m_uuid,
  319. 1,
  320. &light->m_shadowRenderQueue->m_shadowRenderablesLastUpdateTimestamp,
  321. &faceIdx,
  322. &localDrawcallCount,
  323. &tileIdx,
  324. &scratchTileIdx);
  325. if(!allocationFailed)
  326. {
  327. // All good, update the light
  328. // Update the texture matrix to point to the correct region in the atlas
  329. light->m_textureMatrix = createSpotLightTextureMatrix(m_tiles[tileIdx]) * light->m_textureMatrix;
  330. if(scratchTileIdx != MAX_U32)
  331. {
  332. newScratchAndEsmResloveRenderWorkItems(
  333. tileIdx, scratchTileIdx, light->m_shadowRenderQueue, lightsToRender, esmWorkItems, drawcallCount);
  334. }
  335. }
  336. else
  337. {
  338. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  339. light->m_shadowRenderQueue = nullptr;
  340. }
  341. }
  342. // Split the work that will happen in the scratch buffer
  343. if(lightsToRender.getSize())
  344. {
  345. DynamicArrayAuto<ScratchBufferWorkItem> workItems(ctx.m_tempAllocator);
  346. LightToRenderToScratchInfo* lightToRender = lightsToRender.getBegin();
  347. U lightToRenderDrawcallCount = lightToRender->m_drawcallCount;
  348. const LightToRenderToScratchInfo* lightToRenderEnd = lightsToRender.getEnd();
  349. const U threadCount = computeNumberOfSecondLevelCommandBuffers(drawcallCount);
  350. threadCountForScratchPass = threadCount;
  351. for(U taskId = 0; taskId < threadCount; ++taskId)
  352. {
  353. PtrSize start, end;
  354. ThreadPoolTask::choseStartEnd(taskId, threadCount, drawcallCount, start, end);
  355. // While there are drawcalls in this task emit new work items
  356. U taskDrawcallCount = end - start;
  357. ANKI_ASSERT(taskDrawcallCount > 0 && "Because we used computeNumberOfSecondLevelCommandBuffers()");
  358. while(taskDrawcallCount)
  359. {
  360. ANKI_ASSERT(lightToRender != lightToRenderEnd);
  361. const U workItemDrawcallCount = min(lightToRenderDrawcallCount, taskDrawcallCount);
  362. ScratchBufferWorkItem workItem;
  363. workItem.m_viewport = lightToRender->m_viewport;
  364. workItem.m_renderQueue = lightToRender->m_renderQueue;
  365. workItem.m_firstRenderableElement = lightToRender->m_drawcallCount - lightToRenderDrawcallCount;
  366. workItem.m_renderableElementCount = workItemDrawcallCount;
  367. workItem.m_threadPoolTaskIdx = taskId;
  368. workItems.emplaceBack(workItem);
  369. // Decrease the drawcall counts for the task and the light
  370. ANKI_ASSERT(taskDrawcallCount >= workItemDrawcallCount);
  371. taskDrawcallCount -= workItemDrawcallCount;
  372. ANKI_ASSERT(lightToRenderDrawcallCount >= workItemDrawcallCount);
  373. lightToRenderDrawcallCount -= workItemDrawcallCount;
  374. // Move to the next light
  375. if(lightToRenderDrawcallCount == 0)
  376. {
  377. ++lightToRender;
  378. lightToRenderDrawcallCount =
  379. (lightToRender != lightToRenderEnd) ? lightToRender->m_drawcallCount : 0;
  380. }
  381. }
  382. }
  383. ANKI_ASSERT(lightToRender == lightToRenderEnd);
  384. ANKI_ASSERT(lightsToRender.getSize() <= workItems.getSize());
  385. // All good, store the work items for the threads to pick up
  386. {
  387. ScratchBufferWorkItem* items;
  388. PtrSize itemSize;
  389. PtrSize itemStorageSize;
  390. workItems.moveAndReset(items, itemSize, itemStorageSize);
  391. ANKI_ASSERT(items && itemSize && itemStorageSize);
  392. m_scratchWorkItems = WeakArray<ScratchBufferWorkItem>(items, itemSize);
  393. EsmResolveWorkItem* esmItems;
  394. esmWorkItems.moveAndReset(esmItems, itemSize, itemStorageSize);
  395. ANKI_ASSERT(esmItems && itemSize && itemStorageSize);
  396. m_esmResolveWorkItems = WeakArray<EsmResolveWorkItem>(esmItems, itemSize);
  397. }
  398. }
  399. else
  400. {
  401. m_scratchWorkItems = WeakArray<ScratchBufferWorkItem>();
  402. m_esmResolveWorkItems = WeakArray<EsmResolveWorkItem>();
  403. }
  404. }
  405. void ShadowMapping::newScratchAndEsmResloveRenderWorkItems(U32 tileIdx,
  406. U32 scratchTileIdx,
  407. RenderQueue* lightRenderQueue,
  408. DynamicArrayAuto<LightToRenderToScratchInfo>& scratchWorkItem,
  409. DynamicArrayAuto<EsmResolveWorkItem>& esmResolveWorkItem,
  410. U32& drawcallCount) const
  411. {
  412. // Scratch work item
  413. {
  414. Array<U32, 4> viewport;
  415. viewport[0] = scratchTileIdx * m_scratchTileResolution;
  416. viewport[1] = 0;
  417. viewport[2] = m_scratchTileResolution;
  418. viewport[3] = m_scratchTileResolution;
  419. LightToRenderToScratchInfo toRender = {
  420. viewport, lightRenderQueue, U32(lightRenderQueue->m_renderables.getSize())};
  421. scratchWorkItem.emplaceBack(toRender);
  422. drawcallCount += lightRenderQueue->m_renderables.getSize();
  423. }
  424. // ESM resolve work item
  425. {
  426. EsmResolveWorkItem esmItem;
  427. esmItem.m_uvIn[0] = F32(scratchTileIdx) / m_scratchTileCount;
  428. esmItem.m_uvIn[1] = 0.0f;
  429. esmItem.m_uvIn[2] = 1.0f / m_scratchTileCount;
  430. esmItem.m_uvIn[3] = 1.0f;
  431. esmItem.m_viewportOut = m_tiles[tileIdx].m_viewport;
  432. esmItem.m_cameraFar = lightRenderQueue->m_cameraFar;
  433. esmItem.m_cameraNear = lightRenderQueue->m_cameraNear;
  434. esmResolveWorkItem.emplaceBack(esmItem);
  435. }
  436. }
  437. Bool ShadowMapping::allocateTilesAndScratchTiles(U64 lightUuid,
  438. U32 faceCount,
  439. const U64* faceTimestamps,
  440. const U32* faceIndices,
  441. const U32* drawcallsCount,
  442. U32* tileIndices,
  443. U32* scratchTileIndices)
  444. {
  445. ANKI_ASSERT(faceTimestamps);
  446. ANKI_ASSERT(lightUuid > 0);
  447. ANKI_ASSERT(faceCount > 0 && faceCount <= 6);
  448. ANKI_ASSERT(faceIndices && tileIndices && scratchTileIndices && drawcallsCount);
  449. Bool failed = false;
  450. Array<Bool, 6> inTheCache;
  451. // Allocate ESM tiles
  452. {
  453. memset(tileIndices, 0xFF, sizeof(*tileIndices) * faceCount);
  454. for(U i = 0; i < faceCount && !failed; ++i)
  455. {
  456. failed = allocateTile(faceTimestamps[i], lightUuid, faceIndices[i], tileIndices[i], inTheCache[i]);
  457. }
  458. // Unpin the tiles
  459. for(U i = 0; i < faceCount; ++i)
  460. {
  461. if(tileIndices[i] != MAX_U32)
  462. {
  463. m_tiles[tileIndices[i]].m_pinned = false;
  464. }
  465. }
  466. }
  467. // Allocate scratch tiles
  468. {
  469. U32 freeScratchTiles = m_freeScratchTiles;
  470. for(U i = 0; i < faceCount && !failed; ++i)
  471. {
  472. scratchTileIndices[i] = MAX_U32;
  473. const Bool shouldRender = shouldRenderTile(
  474. faceTimestamps[i], lightUuid, faceIndices[i], m_tiles[tileIndices[i]], drawcallsCount[i]);
  475. const Bool scratchTileFailed = shouldRender && freeScratchTiles == 0;
  476. if(scratchTileFailed)
  477. {
  478. ANKI_R_LOGW("Don't have enough space in the scratch shadow mapping buffer. "
  479. "If you see this message too often increase r.shadowMapping.scratchTileCount");
  480. failed = true;
  481. }
  482. else if(shouldRender)
  483. {
  484. ANKI_ASSERT(m_scratchTileCount >= freeScratchTiles);
  485. scratchTileIndices[i] = m_scratchTileCount - freeScratchTiles;
  486. --freeScratchTiles;
  487. }
  488. }
  489. if(!failed)
  490. {
  491. m_freeScratchTiles = freeScratchTiles;
  492. }
  493. }
  494. // Update the tiles if everything was successful
  495. if(!failed)
  496. {
  497. for(U i = 0; i < faceCount; ++i)
  498. {
  499. Tile& tile = m_tiles[tileIndices[i]];
  500. tile.m_face = faceIndices[i];
  501. tile.m_lightUuid = lightUuid;
  502. tile.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
  503. tile.m_drawcallCount = drawcallsCount[i];
  504. // Update the cache
  505. if(!inTheCache[i])
  506. {
  507. TileKey key{lightUuid, faceIndices[i]};
  508. ANKI_ASSERT(m_lightUuidToTileIdx.find(key) == m_lightUuidToTileIdx.getEnd());
  509. m_lightUuidToTileIdx.emplace(getAllocator(), key, tileIndices[i]);
  510. }
  511. }
  512. }
  513. return failed;
  514. }
  515. Bool ShadowMapping::shouldRenderTile(
  516. U64 lightTimestamp, U64 lightUuid, U32 face, const Tile& tileIdx, U32 drawcallCount)
  517. {
  518. if(tileIdx.m_face == face && tileIdx.m_lightUuid == lightUuid && tileIdx.m_lastUsedTimestamp >= lightTimestamp
  519. && tileIdx.m_drawcallCount == drawcallCount)
  520. {
  521. return false;
  522. }
  523. else
  524. {
  525. return true;
  526. }
  527. }
  528. Bool ShadowMapping::allocateTile(U64 lightTimestamp, U64 lightUuid, U32 face, U32& tileAllocated, Bool& inTheCache)
  529. {
  530. ANKI_ASSERT(lightTimestamp > 0);
  531. ANKI_ASSERT(lightUuid > 0);
  532. ANKI_ASSERT(face < 6);
  533. // First, try to see if the light/face is in the cache
  534. inTheCache = false;
  535. TileKey key = TileKey{lightUuid, U64(face)};
  536. auto it = m_lightUuidToTileIdx.find(key);
  537. if(it != m_lightUuidToTileIdx.getEnd())
  538. {
  539. const U32 tileIdx = *it;
  540. if(m_tiles[tileIdx].m_lightUuid == lightUuid && m_tiles[tileIdx].m_face == face && !m_tiles[tileIdx].m_pinned)
  541. {
  542. // Found it
  543. tileAllocated = tileIdx;
  544. inTheCache = true;
  545. return false;
  546. }
  547. else
  548. {
  549. // Cache entry is wrong, remove it
  550. m_lightUuidToTileIdx.erase(getAllocator(), it);
  551. }
  552. }
  553. // 2nd and 3rd choice, find an empty tile or some tile to re-use
  554. U32 emptyTile = MAX_U32;
  555. U32 tileToKick = MAX_U32;
  556. Timestamp tileToKickMinTimestamp = MAX_TIMESTAMP;
  557. for(U32 tileIdx = 0; tileIdx < m_tiles.getSize(); ++tileIdx)
  558. {
  559. if(m_tiles[tileIdx].m_pinned)
  560. {
  561. continue;
  562. }
  563. if(m_tiles[tileIdx].m_lightUuid == 0)
  564. {
  565. // Found an empty
  566. emptyTile = tileIdx;
  567. break;
  568. }
  569. else if(m_tiles[tileIdx].m_lastUsedTimestamp != m_r->getGlobalTimestamp()
  570. && m_tiles[tileIdx].m_lastUsedTimestamp < tileToKickMinTimestamp)
  571. {
  572. // Found some with low timestamp
  573. tileToKick = tileIdx;
  574. tileToKickMinTimestamp = m_tiles[tileIdx].m_lastUsedTimestamp;
  575. }
  576. }
  577. Bool failed = false;
  578. if(emptyTile != MAX_U32)
  579. {
  580. tileAllocated = emptyTile;
  581. }
  582. else if(tileToKick != MAX_U32)
  583. {
  584. tileAllocated = tileToKick;
  585. }
  586. else
  587. {
  588. // We have a problem
  589. failed = true;
  590. ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. "
  591. "Increase the r.shadowMapping.tileCountPerRowOrColumn or decrease the scene's shadow casters");
  592. }
  593. if(!failed)
  594. {
  595. ANKI_ASSERT(!m_tiles[tileAllocated].m_pinned);
  596. m_tiles[tileAllocated].m_pinned = true;
  597. }
  598. return failed;
  599. }
  600. } // end namespace anki