ShadowMapping.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. // Copyright (C) 2009-2019, 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/ThreadHive.h>
  12. namespace anki
  13. {
  14. class ShadowMapping::ScratchBufferWorkItem
  15. {
  16. public:
  17. Array<U32, 4> m_viewport;
  18. RenderQueue* m_renderQueue;
  19. U32 m_firstRenderableElement;
  20. U32 m_renderableElementCount;
  21. U32 m_threadPoolTaskIdx;
  22. };
  23. class ShadowMapping::LightToRenderToScratchInfo
  24. {
  25. public:
  26. Array<U32, 4> m_viewport;
  27. RenderQueue* m_renderQueue;
  28. U32 m_drawcallCount;
  29. };
  30. class ShadowMapping::EsmResolveWorkItem
  31. {
  32. public:
  33. Vec4 m_uvIn; ///< UV + size that point to the scratch buffer.
  34. Array<U32, 4> m_viewportOut; ///< Viewport in the ESM RT.
  35. F32 m_cameraNear;
  36. F32 m_cameraFar;
  37. Bool m_blur;
  38. Bool m_perspectiveProjection;
  39. };
  40. ShadowMapping::~ShadowMapping()
  41. {
  42. }
  43. Error ShadowMapping::init(const ConfigSet& config)
  44. {
  45. ANKI_R_LOGI("Initializing shadowmapping");
  46. Error err = initInternal(config);
  47. if(err)
  48. {
  49. ANKI_R_LOGE("Failed to initialize shadowmapping");
  50. }
  51. ANKI_R_LOGI("\tScratch size %ux%u. ESM atlas size %ux%u",
  52. m_scratchTileCountX * m_scratchTileResolution,
  53. m_scratchTileCountY * m_scratchTileResolution,
  54. m_esmTileCountBothAxis * m_esmTileResolution,
  55. m_esmTileCountBothAxis * m_esmTileResolution);
  56. return err;
  57. }
  58. Error ShadowMapping::initScratch(const ConfigSet& cfg)
  59. {
  60. // Init the shadowmaps and FBs
  61. {
  62. m_scratchTileCountX = cfg.getNumber("r.shadowMapping.scratchTileCountX");
  63. m_scratchTileCountY = cfg.getNumber("r.shadowMapping.scratchTileCountY");
  64. m_scratchTileResolution = cfg.getNumber("r.shadowMapping.tileResolution");
  65. // RT
  66. m_scratchRtDescr = m_r->create2DRenderTargetDescription(m_scratchTileResolution * m_scratchTileCountX,
  67. m_scratchTileResolution * m_scratchTileCountY,
  68. SHADOW_DEPTH_PIXEL_FORMAT,
  69. "Scratch ShadMap");
  70. m_scratchRtDescr.bake();
  71. // FB
  72. m_scratchFbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::CLEAR;
  73. m_scratchFbDescr.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0f;
  74. m_scratchFbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
  75. m_scratchFbDescr.bake();
  76. }
  77. m_scratchTileAlloc.init(getAllocator(), m_scratchTileCountX, m_scratchTileCountY, m_lodCount, false);
  78. return Error::NONE;
  79. }
  80. Error ShadowMapping::initEsm(const ConfigSet& cfg)
  81. {
  82. // Init RTs and FBs
  83. {
  84. m_esmTileResolution = cfg.getNumber("r.shadowMapping.tileResolution");
  85. m_esmTileCountBothAxis = cfg.getNumber("r.shadowMapping.tileCountPerRowOrColumn");
  86. // RT
  87. TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(m_esmTileResolution * m_esmTileCountBothAxis,
  88. m_esmTileResolution * m_esmTileCountBothAxis,
  89. SHADOW_COLOR_PIXEL_FORMAT,
  90. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE
  91. | TextureUsageBit::SAMPLED_COMPUTE,
  92. "esm");
  93. texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
  94. ClearValue clearVal;
  95. clearVal.m_colorf[0] = 1.0f;
  96. m_esmAtlas = m_r->createAndClearRenderTarget(texinit, clearVal);
  97. // FB
  98. m_esmFbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::LOAD;
  99. m_esmFbDescr.m_colorAttachmentCount = 1;
  100. m_esmFbDescr.bake();
  101. }
  102. // Tiles
  103. m_esmTileAlloc.init(getAllocator(), m_esmTileCountBothAxis, m_esmTileCountBothAxis, m_lodCount, true);
  104. // Programs and shaders
  105. {
  106. ANKI_CHECK(
  107. getResourceManager().loadResource("shaders/ExponentialShadowmappingResolve.glslp", m_esmResolveProg));
  108. ShaderProgramResourceConstantValueInitList<1> consts(m_esmResolveProg);
  109. consts.add("INPUT_TEXTURE_SIZE",
  110. UVec2(m_scratchTileCountX * m_scratchTileResolution, m_scratchTileCountY * m_scratchTileResolution));
  111. const ShaderProgramResourceVariant* variant;
  112. m_esmResolveProg->getOrCreateVariant(consts.get(), variant);
  113. m_esmResolveGrProg = variant->getProgram();
  114. }
  115. return Error::NONE;
  116. }
  117. Error ShadowMapping::initInternal(const ConfigSet& cfg)
  118. {
  119. ANKI_CHECK(initScratch(cfg));
  120. ANKI_CHECK(initEsm(cfg));
  121. m_lodDistances[0] = cfg.getNumber("r.shadowMapping.lightLodDistance0");
  122. m_lodDistances[1] = cfg.getNumber("r.shadowMapping.lightLodDistance1");
  123. return Error::NONE;
  124. }
  125. void ShadowMapping::runEsm(RenderPassWorkContext& rgraphCtx)
  126. {
  127. ANKI_ASSERT(m_esmResolveWorkItems.getSize());
  128. ANKI_TRACE_SCOPED_EVENT(R_SM);
  129. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  130. cmdb->bindShaderProgram(m_esmResolveGrProg);
  131. cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
  132. rgraphCtx.bindTexture(0, 1, m_scratchRt, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
  133. for(const EsmResolveWorkItem& workItem : m_esmResolveWorkItems)
  134. {
  135. ANKI_TRACE_INC_COUNTER(R_SHADOW_PASSES, 1);
  136. cmdb->setViewport(
  137. workItem.m_viewportOut[0], workItem.m_viewportOut[1], workItem.m_viewportOut[2], workItem.m_viewportOut[3]);
  138. cmdb->setScissor(
  139. workItem.m_viewportOut[0], workItem.m_viewportOut[1], workItem.m_viewportOut[2], workItem.m_viewportOut[3]);
  140. struct Uniforms
  141. {
  142. Vec2 m_uvScale;
  143. Vec2 m_uvTranslation;
  144. F32 m_near;
  145. F32 m_far;
  146. U32 m_renderingTechnique;
  147. U32 m_padding;
  148. } unis;
  149. unis.m_uvScale = workItem.m_uvIn.zw();
  150. unis.m_uvTranslation = workItem.m_uvIn.xy();
  151. unis.m_near = workItem.m_cameraNear;
  152. unis.m_far = workItem.m_cameraFar;
  153. if(workItem.m_perspectiveProjection)
  154. {
  155. unis.m_renderingTechnique = (workItem.m_blur) ? 0 : 1;
  156. }
  157. else
  158. {
  159. unis.m_renderingTechnique = (workItem.m_blur) ? 2 : 3;
  160. }
  161. cmdb->setPushConstants(&unis, sizeof(unis));
  162. drawQuad(cmdb);
  163. }
  164. // Restore GR state
  165. cmdb->setScissor(0, 0, MAX_U32, MAX_U32);
  166. }
  167. void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  168. {
  169. ANKI_ASSERT(m_scratchWorkItems.getSize());
  170. ANKI_TRACE_SCOPED_EVENT(R_SM);
  171. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  172. const U threadIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
  173. for(ScratchBufferWorkItem& work : m_scratchWorkItems)
  174. {
  175. if(work.m_threadPoolTaskIdx != threadIdx)
  176. {
  177. continue;
  178. }
  179. // Set state
  180. cmdb->setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  181. cmdb->setScissor(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  182. m_r->getSceneDrawer().drawRange(Pass::SM,
  183. work.m_renderQueue->m_viewMatrix,
  184. work.m_renderQueue->m_viewProjectionMatrix,
  185. Mat4::getIdentity(), // Don't care about prev matrices here
  186. cmdb,
  187. m_r->getSamplers().m_trilinearRepeatAniso,
  188. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement,
  189. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement
  190. + work.m_renderableElementCount,
  191. MAX_LOD_COUNT - 1);
  192. }
  193. }
  194. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  195. {
  196. ANKI_TRACE_SCOPED_EVENT(R_SM);
  197. // First process the lights
  198. U32 threadCountForScratchPass = 0;
  199. processLights(ctx, threadCountForScratchPass);
  200. // Build the render graph
  201. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  202. if(m_scratchWorkItems.getSize())
  203. {
  204. // Will have to create render passes
  205. // Scratch pass
  206. {
  207. // Compute render area
  208. const U32 minx = 0, miny = 0;
  209. const U32 height = m_scratchMaxViewportHeight;
  210. const U32 width = m_scratchMaxViewportWidth;
  211. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SM scratch");
  212. m_scratchRt = rgraph.newRenderTarget(m_scratchRtDescr);
  213. pass.setFramebufferInfo(m_scratchFbDescr, {}, m_scratchRt, minx, miny, width, height);
  214. ANKI_ASSERT(
  215. threadCountForScratchPass && threadCountForScratchPass <= m_r->getThreadHive().getThreadCount());
  216. pass.setWork(
  217. [](RenderPassWorkContext& rgraphCtx) {
  218. static_cast<ShadowMapping*>(rgraphCtx.m_userData)->runShadowMapping(rgraphCtx);
  219. },
  220. this,
  221. threadCountForScratchPass);
  222. TextureSubresourceInfo subresource = TextureSubresourceInfo(DepthStencilAspectBit::DEPTH);
  223. pass.newDependency({m_scratchRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
  224. }
  225. // ESM pass
  226. {
  227. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("ESM");
  228. m_esmRt = rgraph.importRenderTarget(m_esmAtlas, TextureUsageBit::SAMPLED_FRAGMENT);
  229. pass.setFramebufferInfo(m_esmFbDescr, {{m_esmRt}}, {});
  230. pass.setWork(
  231. [](RenderPassWorkContext& rgraphCtx) {
  232. static_cast<ShadowMapping*>(rgraphCtx.m_userData)->runEsm(rgraphCtx);
  233. },
  234. this,
  235. 0);
  236. pass.newDependency(
  237. {m_scratchRt, TextureUsageBit::SAMPLED_FRAGMENT, TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
  238. pass.newDependency({m_esmRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
  239. }
  240. }
  241. else
  242. {
  243. // No need for shadowmapping passes, just import the ESM atlas
  244. m_esmRt = rgraph.importRenderTarget(m_esmAtlas, TextureUsageBit::SAMPLED_FRAGMENT);
  245. }
  246. }
  247. Mat4 ShadowMapping::createSpotLightTextureMatrix(const Viewport& viewport) const
  248. {
  249. const F32 atlasSize = m_esmTileResolution * m_esmTileCountBothAxis;
  250. const Vec2 uv(F32(viewport[0]) / atlasSize, F32(viewport[1]) / atlasSize);
  251. ANKI_ASSERT(uv >= Vec2(0.0f) && uv <= Vec2(1.0f));
  252. ANKI_ASSERT(viewport[2] == viewport[3]);
  253. const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
  254. return Mat4(sizeTextureSpace,
  255. 0.0f,
  256. 0.0f,
  257. uv.x(),
  258. 0.0f,
  259. sizeTextureSpace,
  260. 0.0f,
  261. uv.y(),
  262. 0.0f,
  263. 0.0f,
  264. 1.0f,
  265. 0.0f,
  266. 0.0f,
  267. 0.0f,
  268. 0.0f,
  269. 1.0f);
  270. }
  271. U ShadowMapping::choseLod(const Vec4& cameraOrigin, const PointLightQueueElement& light, Bool& blurEsm) const
  272. {
  273. const F32 distFromTheCamera = (cameraOrigin - light.m_worldPosition.xyz0()).getLength() - light.m_radius;
  274. if(distFromTheCamera < m_lodDistances[0])
  275. {
  276. ANKI_ASSERT(m_pointLightsMaxLod == 1);
  277. blurEsm = true;
  278. return 1;
  279. }
  280. else
  281. {
  282. blurEsm = false;
  283. return 0;
  284. }
  285. }
  286. U ShadowMapping::choseLod(const Vec4& cameraOrigin, const SpotLightQueueElement& light, Bool& blurEsm) const
  287. {
  288. // Get some data
  289. const Vec4 coneOrigin = light.m_worldTransform.getTranslationPart().xyz0();
  290. const Vec4 coneDir = -light.m_worldTransform.getZAxis().xyz0();
  291. const F32 coneAngle = light.m_outerAngle;
  292. // Compute the distance from the camera to the light cone
  293. const Vec4 V = cameraOrigin - coneOrigin;
  294. const F32 VlenSq = V.dot(V);
  295. const F32 V1len = V.dot(coneDir);
  296. const F32 distFromTheCamera = cos(coneAngle) * sqrt(VlenSq - V1len * V1len) - V1len * sin(coneAngle);
  297. U lod;
  298. if(distFromTheCamera < m_lodDistances[0])
  299. {
  300. blurEsm = true;
  301. lod = 2;
  302. }
  303. else if(distFromTheCamera < m_lodDistances[1])
  304. {
  305. blurEsm = false;
  306. lod = 1;
  307. }
  308. else
  309. {
  310. blurEsm = false;
  311. lod = 0;
  312. }
  313. return lod;
  314. }
  315. TileAllocatorResult ShadowMapping::allocateTilesAndScratchTiles(U64 lightUuid,
  316. U32 faceCount,
  317. const U64* faceTimestamps,
  318. const U32* faceIndices,
  319. const U32* drawcallsCount,
  320. const U32* lods,
  321. Viewport* esmTileViewports,
  322. Viewport* scratchTileViewports,
  323. TileAllocatorResult* subResults)
  324. {
  325. ANKI_ASSERT(lightUuid > 0);
  326. ANKI_ASSERT(faceCount > 0);
  327. ANKI_ASSERT(faceTimestamps);
  328. ANKI_ASSERT(faceIndices);
  329. ANKI_ASSERT(drawcallsCount);
  330. ANKI_ASSERT(lods);
  331. TileAllocatorResult res;
  332. // Allocate ESM tiles first. They may be cached and that will affect how many scratch tiles we'll need
  333. for(U i = 0; i < faceCount; ++i)
  334. {
  335. res = m_esmTileAlloc.allocate(m_r->getGlobalTimestamp(),
  336. faceTimestamps[i],
  337. lightUuid,
  338. faceIndices[i],
  339. drawcallsCount[i],
  340. lods[i],
  341. esmTileViewports[i]);
  342. if(res == TileAllocatorResult::ALLOCATION_FAILED)
  343. {
  344. ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. "
  345. "Increase the r.shadowMapping.tileCountPerRowOrColumn or decrease the scene's shadow casters");
  346. // Invalidate cache entries for what we already allocated
  347. for(U j = 0; j < i; ++j)
  348. {
  349. m_esmTileAlloc.invalidateCache(lightUuid, faceIndices[j]);
  350. }
  351. return res;
  352. }
  353. subResults[i] = res;
  354. // Fix viewport
  355. esmTileViewports[i][0] *= m_esmTileResolution;
  356. esmTileViewports[i][1] *= m_esmTileResolution;
  357. esmTileViewports[i][2] *= m_esmTileResolution;
  358. esmTileViewports[i][3] *= m_esmTileResolution;
  359. }
  360. // Allocate scratch tiles
  361. for(U i = 0; i < faceCount; ++i)
  362. {
  363. if(subResults[i] == TileAllocatorResult::CACHED)
  364. {
  365. continue;
  366. }
  367. ANKI_ASSERT(subResults[i] == TileAllocatorResult::ALLOCATION_SUCCEEDED);
  368. res = m_scratchTileAlloc.allocate(m_r->getGlobalTimestamp(),
  369. faceTimestamps[i],
  370. lightUuid,
  371. faceIndices[i],
  372. drawcallsCount[i],
  373. lods[i],
  374. scratchTileViewports[i]);
  375. if(res == TileAllocatorResult::ALLOCATION_FAILED)
  376. {
  377. ANKI_R_LOGW("Don't have enough space in the scratch shadow mapping buffer. "
  378. "If you see this message too often increase r.shadowMapping.scratchTileCountX/Y");
  379. // Invalidate ESM tiles
  380. for(U j = 0; j < faceCount; ++j)
  381. {
  382. m_esmTileAlloc.invalidateCache(lightUuid, faceIndices[j]);
  383. }
  384. return res;
  385. }
  386. // Fix viewport
  387. scratchTileViewports[i][0] *= m_scratchTileResolution;
  388. scratchTileViewports[i][1] *= m_scratchTileResolution;
  389. scratchTileViewports[i][2] *= m_scratchTileResolution;
  390. scratchTileViewports[i][3] *= m_scratchTileResolution;
  391. // Update the max view width
  392. m_scratchMaxViewportWidth =
  393. max(m_scratchMaxViewportWidth, scratchTileViewports[i][0] + scratchTileViewports[i][2]);
  394. m_scratchMaxViewportHeight =
  395. max(m_scratchMaxViewportHeight, scratchTileViewports[i][1] + scratchTileViewports[i][3]);
  396. }
  397. return res;
  398. }
  399. void ShadowMapping::processLights(RenderingContext& ctx, U32& threadCountForScratchPass)
  400. {
  401. // Reset the scratch viewport width
  402. m_scratchMaxViewportWidth = 0;
  403. m_scratchMaxViewportHeight = 0;
  404. // Vars
  405. const Vec4 cameraOrigin = ctx.m_renderQueue->m_cameraTransform.getTranslationPart().xyz0();
  406. DynamicArrayAuto<LightToRenderToScratchInfo> lightsToRender(ctx.m_tempAllocator);
  407. U32 drawcallCount = 0;
  408. DynamicArrayAuto<EsmResolveWorkItem> esmWorkItems(ctx.m_tempAllocator);
  409. // First thing, allocate an empty tile for empty faces of point lights
  410. Viewport emptyTileViewport;
  411. {
  412. const TileAllocatorResult res = m_esmTileAlloc.allocate(
  413. m_r->getGlobalTimestamp(), 1, MAX_U64, 0, 1, m_pointLightsMaxLod, emptyTileViewport);
  414. (void)res;
  415. #if ANKI_ASSERTS_ENABLED
  416. static Bool firstRun = true;
  417. if(firstRun)
  418. {
  419. ANKI_ASSERT(res == TileAllocatorResult::ALLOCATION_SUCCEEDED);
  420. firstRun = false;
  421. }
  422. else
  423. {
  424. ANKI_ASSERT(res == TileAllocatorResult::CACHED);
  425. }
  426. #endif
  427. }
  428. // Process the directional light first.
  429. if(ctx.m_renderQueue->m_directionalLight.m_shadowCascadeCount > 0)
  430. {
  431. DirectionalLightQueueElement& light = ctx.m_renderQueue->m_directionalLight;
  432. Array<U64, MAX_SHADOW_CASCADES> timestamps;
  433. Array<U32, MAX_SHADOW_CASCADES> cascadeIndices;
  434. Array<U32, MAX_SHADOW_CASCADES> drawcallCounts;
  435. Array<Viewport, MAX_SHADOW_CASCADES> esmViewports;
  436. Array<Viewport, MAX_SHADOW_CASCADES> scratchViewports;
  437. Array<TileAllocatorResult, MAX_SHADOW_CASCADES> subResults;
  438. Array<U32, MAX_SHADOW_CASCADES> lods;
  439. Array<Bool, MAX_SHADOW_CASCADES> blurEsms;
  440. U activeCascades = 0;
  441. for(U cascade = 0; cascade < light.m_shadowCascadeCount; ++cascade)
  442. {
  443. ANKI_ASSERT(light.m_shadowRenderQueues[cascade]);
  444. if(light.m_shadowRenderQueues[cascade]->m_renderables.getSize() > 0)
  445. {
  446. // Cascade with drawcalls, will need tiles
  447. timestamps[activeCascades] = m_r->getGlobalTimestamp(); // This light is always updated
  448. cascadeIndices[activeCascades] = cascade;
  449. drawcallCounts[activeCascades] = 1; // Doesn't matter
  450. // Change the quality per cascade
  451. blurEsms[activeCascades] = (cascade <= 1);
  452. lods[activeCascades] = (cascade <= 1) ? (m_lodCount - 1) : (lods[0] - 1);
  453. ++activeCascades;
  454. }
  455. }
  456. const Bool allocationFailed = activeCascades == 0
  457. || allocateTilesAndScratchTiles(light.m_uuid,
  458. activeCascades,
  459. &timestamps[0],
  460. &cascadeIndices[0],
  461. &drawcallCounts[0],
  462. &lods[0],
  463. &esmViewports[0],
  464. &scratchViewports[0],
  465. &subResults[0])
  466. == TileAllocatorResult::ALLOCATION_FAILED;
  467. if(!allocationFailed)
  468. {
  469. activeCascades = 0;
  470. for(U cascade = 0; cascade < light.m_shadowCascadeCount; ++cascade)
  471. {
  472. if(light.m_shadowRenderQueues[cascade]->m_renderables.getSize() > 0)
  473. {
  474. // Cascade with drawcalls, push some work for it
  475. // Update the texture matrix to point to the correct region in the atlas
  476. light.m_textureMatrices[cascade] =
  477. createSpotLightTextureMatrix(esmViewports[activeCascades]) * light.m_textureMatrices[cascade];
  478. // Push work
  479. newScratchAndEsmResloveRenderWorkItems(esmViewports[activeCascades],
  480. scratchViewports[activeCascades],
  481. blurEsms[activeCascades],
  482. false,
  483. light.m_shadowRenderQueues[cascade],
  484. lightsToRender,
  485. esmWorkItems,
  486. drawcallCount);
  487. ++activeCascades;
  488. }
  489. else
  490. {
  491. // Empty cascade, point it to the empty tile
  492. light.m_textureMatrices[cascade] =
  493. createSpotLightTextureMatrix(emptyTileViewport) * light.m_textureMatrices[cascade];
  494. }
  495. }
  496. }
  497. else
  498. {
  499. // Light can't be a caster this frame
  500. light.m_shadowCascadeCount = 0;
  501. zeroMemory(light.m_shadowRenderQueues);
  502. }
  503. }
  504. // Process the point lights.
  505. for(PointLightQueueElement* light : ctx.m_renderQueue->m_shadowPointLights)
  506. {
  507. // Prepare data to allocate tiles and allocate
  508. Array<U64, 6> timestamps;
  509. Array<U32, 6> faceIndices;
  510. Array<U32, 6> drawcallCounts;
  511. Array<Viewport, 6> esmViewports;
  512. Array<Viewport, 6> scratchViewports;
  513. Array<TileAllocatorResult, 6> subResults;
  514. Array<U32, 6> lods;
  515. U numOfFacesThatHaveDrawcalls = 0;
  516. Bool blurEsm;
  517. const U lod = choseLod(cameraOrigin, *light, blurEsm);
  518. for(U face = 0; face < 6; ++face)
  519. {
  520. ANKI_ASSERT(light->m_shadowRenderQueues[face]);
  521. if(light->m_shadowRenderQueues[face]->m_renderables.getSize())
  522. {
  523. // Has renderables, need to allocate tiles for it so add it to the arrays
  524. faceIndices[numOfFacesThatHaveDrawcalls] = face;
  525. timestamps[numOfFacesThatHaveDrawcalls] =
  526. light->m_shadowRenderQueues[face]->m_shadowRenderablesLastUpdateTimestamp;
  527. drawcallCounts[numOfFacesThatHaveDrawcalls] =
  528. light->m_shadowRenderQueues[face]->m_renderables.getSize();
  529. lods[numOfFacesThatHaveDrawcalls] = lod;
  530. ++numOfFacesThatHaveDrawcalls;
  531. }
  532. }
  533. const Bool allocationFailed = numOfFacesThatHaveDrawcalls == 0
  534. || allocateTilesAndScratchTiles(light->m_uuid,
  535. numOfFacesThatHaveDrawcalls,
  536. &timestamps[0],
  537. &faceIndices[0],
  538. &drawcallCounts[0],
  539. &lods[0],
  540. &esmViewports[0],
  541. &scratchViewports[0],
  542. &subResults[0])
  543. == TileAllocatorResult::ALLOCATION_FAILED;
  544. if(!allocationFailed)
  545. {
  546. // All good, update the lights
  547. const F32 atlasResolution = F32(m_esmTileResolution * m_esmTileCountBothAxis);
  548. F32 superTileSize = esmViewports[0][2]; // Should be the same for all tiles and faces
  549. superTileSize -= 1.0f; // Remove 2 half texels to avoid bilinear filtering bleeding
  550. light->m_shadowAtlasTileSize = superTileSize / atlasResolution;
  551. numOfFacesThatHaveDrawcalls = 0;
  552. for(U face = 0; face < 6; ++face)
  553. {
  554. if(light->m_shadowRenderQueues[face]->m_renderables.getSize())
  555. {
  556. // Has drawcalls, asigned it to a tile
  557. const Viewport& esmViewport = esmViewports[numOfFacesThatHaveDrawcalls];
  558. const Viewport& scratchViewport = scratchViewports[numOfFacesThatHaveDrawcalls];
  559. // Add a half texel to the viewport's start to avoid bilinear filtering bleeding
  560. light->m_shadowAtlasTileOffsets[face].x() = (F32(esmViewport[0]) + 0.5f) / atlasResolution;
  561. light->m_shadowAtlasTileOffsets[face].y() = (F32(esmViewport[1]) + 0.5f) / atlasResolution;
  562. if(subResults[numOfFacesThatHaveDrawcalls] != TileAllocatorResult::CACHED)
  563. {
  564. newScratchAndEsmResloveRenderWorkItems(esmViewport,
  565. scratchViewport,
  566. blurEsm,
  567. true,
  568. light->m_shadowRenderQueues[face],
  569. lightsToRender,
  570. esmWorkItems,
  571. drawcallCount);
  572. }
  573. ++numOfFacesThatHaveDrawcalls;
  574. }
  575. else
  576. {
  577. // Doesn't have renderables, point the face to the empty tile
  578. Viewport esmViewport = emptyTileViewport;
  579. ANKI_ASSERT(esmViewport[2] <= superTileSize && esmViewport[3] <= superTileSize);
  580. esmViewport[2] = superTileSize;
  581. esmViewport[3] = superTileSize;
  582. light->m_shadowAtlasTileOffsets[face].x() = (F32(esmViewport[0]) + 0.5f) / atlasResolution;
  583. light->m_shadowAtlasTileOffsets[face].y() = (F32(esmViewport[1]) + 0.5f) / atlasResolution;
  584. }
  585. }
  586. }
  587. else
  588. {
  589. // Light can't be a caster this frame
  590. zeroMemory(light->m_shadowRenderQueues);
  591. }
  592. }
  593. // Process the spot lights
  594. for(SpotLightQueueElement* light : ctx.m_renderQueue->m_shadowSpotLights)
  595. {
  596. ANKI_ASSERT(light->m_shadowRenderQueue);
  597. // Allocate tiles
  598. U32 faceIdx = 0;
  599. TileAllocatorResult subResult;
  600. Viewport esmViewport;
  601. Viewport scratchViewport;
  602. const U32 localDrawcallCount = light->m_shadowRenderQueue->m_renderables.getSize();
  603. Bool blurEsm;
  604. const U32 lod = choseLod(cameraOrigin, *light, blurEsm);
  605. const Bool allocationFailed = localDrawcallCount == 0
  606. || allocateTilesAndScratchTiles(light->m_uuid,
  607. 1,
  608. &light->m_shadowRenderQueue->m_shadowRenderablesLastUpdateTimestamp,
  609. &faceIdx,
  610. &localDrawcallCount,
  611. &lod,
  612. &esmViewport,
  613. &scratchViewport,
  614. &subResult)
  615. == TileAllocatorResult::ALLOCATION_FAILED;
  616. if(!allocationFailed)
  617. {
  618. // All good, update the light
  619. // Update the texture matrix to point to the correct region in the atlas
  620. light->m_textureMatrix = createSpotLightTextureMatrix(esmViewport) * light->m_textureMatrix;
  621. if(subResult != TileAllocatorResult::CACHED)
  622. {
  623. newScratchAndEsmResloveRenderWorkItems(esmViewport,
  624. scratchViewport,
  625. blurEsm,
  626. true,
  627. light->m_shadowRenderQueue,
  628. lightsToRender,
  629. esmWorkItems,
  630. drawcallCount);
  631. }
  632. }
  633. else
  634. {
  635. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  636. light->m_shadowRenderQueue = nullptr;
  637. }
  638. }
  639. // Split the work that will happen in the scratch buffer
  640. if(lightsToRender.getSize())
  641. {
  642. DynamicArrayAuto<ScratchBufferWorkItem> workItems(ctx.m_tempAllocator);
  643. LightToRenderToScratchInfo* lightToRender = lightsToRender.getBegin();
  644. U lightToRenderDrawcallCount = lightToRender->m_drawcallCount;
  645. const LightToRenderToScratchInfo* lightToRenderEnd = lightsToRender.getEnd();
  646. const U threadCount = computeNumberOfSecondLevelCommandBuffers(drawcallCount);
  647. threadCountForScratchPass = threadCount;
  648. for(U taskId = 0; taskId < threadCount; ++taskId)
  649. {
  650. PtrSize start, end;
  651. splitThreadedProblem(taskId, threadCount, drawcallCount, start, end);
  652. // While there are drawcalls in this task emit new work items
  653. U taskDrawcallCount = end - start;
  654. ANKI_ASSERT(taskDrawcallCount > 0 && "Because we used computeNumberOfSecondLevelCommandBuffers()");
  655. while(taskDrawcallCount)
  656. {
  657. ANKI_ASSERT(lightToRender != lightToRenderEnd);
  658. const U workItemDrawcallCount = min(lightToRenderDrawcallCount, taskDrawcallCount);
  659. ScratchBufferWorkItem workItem;
  660. workItem.m_viewport = lightToRender->m_viewport;
  661. workItem.m_renderQueue = lightToRender->m_renderQueue;
  662. workItem.m_firstRenderableElement = lightToRender->m_drawcallCount - lightToRenderDrawcallCount;
  663. workItem.m_renderableElementCount = workItemDrawcallCount;
  664. workItem.m_threadPoolTaskIdx = taskId;
  665. workItems.emplaceBack(workItem);
  666. // Decrease the drawcall counts for the task and the light
  667. ANKI_ASSERT(taskDrawcallCount >= workItemDrawcallCount);
  668. taskDrawcallCount -= workItemDrawcallCount;
  669. ANKI_ASSERT(lightToRenderDrawcallCount >= workItemDrawcallCount);
  670. lightToRenderDrawcallCount -= workItemDrawcallCount;
  671. // Move to the next light
  672. if(lightToRenderDrawcallCount == 0)
  673. {
  674. ++lightToRender;
  675. lightToRenderDrawcallCount =
  676. (lightToRender != lightToRenderEnd) ? lightToRender->m_drawcallCount : 0;
  677. }
  678. }
  679. }
  680. ANKI_ASSERT(lightToRender == lightToRenderEnd);
  681. ANKI_ASSERT(lightsToRender.getSize() <= workItems.getSize());
  682. // All good, store the work items for the threads to pick up
  683. {
  684. ScratchBufferWorkItem* items;
  685. PtrSize itemSize;
  686. PtrSize itemStorageSize;
  687. workItems.moveAndReset(items, itemSize, itemStorageSize);
  688. ANKI_ASSERT(items && itemSize && itemStorageSize);
  689. m_scratchWorkItems = WeakArray<ScratchBufferWorkItem>(items, itemSize);
  690. EsmResolveWorkItem* esmItems;
  691. esmWorkItems.moveAndReset(esmItems, itemSize, itemStorageSize);
  692. ANKI_ASSERT(esmItems && itemSize && itemStorageSize);
  693. m_esmResolveWorkItems = WeakArray<EsmResolveWorkItem>(esmItems, itemSize);
  694. }
  695. }
  696. else
  697. {
  698. m_scratchWorkItems = WeakArray<ScratchBufferWorkItem>();
  699. m_esmResolveWorkItems = WeakArray<EsmResolveWorkItem>();
  700. }
  701. }
  702. void ShadowMapping::newScratchAndEsmResloveRenderWorkItems(const Viewport& esmViewport,
  703. const Viewport& scratchVewport,
  704. Bool blurEsm,
  705. Bool perspectiveProjection,
  706. RenderQueue* lightRenderQueue,
  707. DynamicArrayAuto<LightToRenderToScratchInfo>& scratchWorkItem,
  708. DynamicArrayAuto<EsmResolveWorkItem>& esmResolveWorkItem,
  709. U32& drawcallCount) const
  710. {
  711. // Scratch work item
  712. {
  713. LightToRenderToScratchInfo toRender = {
  714. scratchVewport, lightRenderQueue, U32(lightRenderQueue->m_renderables.getSize())};
  715. scratchWorkItem.emplaceBack(toRender);
  716. drawcallCount += lightRenderQueue->m_renderables.getSize();
  717. }
  718. // ESM resolve work item
  719. {
  720. const F32 scratchAtlasWidth = m_scratchTileCountX * m_scratchTileResolution;
  721. const F32 scratchAtlasHeight = m_scratchTileCountY * m_scratchTileResolution;
  722. EsmResolveWorkItem esmItem;
  723. esmItem.m_uvIn[0] = F32(scratchVewport[0]) / scratchAtlasWidth;
  724. esmItem.m_uvIn[1] = F32(scratchVewport[1]) / scratchAtlasHeight;
  725. esmItem.m_uvIn[2] = F32(scratchVewport[2]) / scratchAtlasWidth;
  726. esmItem.m_uvIn[3] = F32(scratchVewport[3]) / scratchAtlasHeight;
  727. esmItem.m_viewportOut = esmViewport;
  728. esmItem.m_cameraFar = lightRenderQueue->m_cameraFar;
  729. esmItem.m_cameraNear = lightRenderQueue->m_cameraNear;
  730. esmItem.m_blur = blurEsm;
  731. esmItem.m_perspectiveProjection = perspectiveProjection;
  732. esmResolveWorkItem.emplaceBack(esmItem);
  733. }
  734. }
  735. } // end namespace anki