ShadowMapping.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Renderer/ShadowMapping.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/RenderQueue.h>
  8. #include <AnKi/Core/ConfigSet.h>
  9. #include <AnKi/Util/ThreadHive.h>
  10. #include <AnKi/Util/Tracer.h>
  11. namespace anki {
  12. class ShadowMapping::LightToRenderTempInfo
  13. {
  14. public:
  15. UVec4 m_viewport;
  16. RenderQueue* m_renderQueue;
  17. U32 m_drawcallCount;
  18. U32 m_renderQueueElementsLod;
  19. };
  20. class ShadowMapping::ThreadWorkItem
  21. {
  22. public:
  23. UVec4 m_viewport;
  24. RenderQueue* m_renderQueue;
  25. U32 m_firstRenderableElement;
  26. U32 m_renderableElementCount;
  27. U32 m_threadPoolTaskIdx;
  28. U32 m_renderQueueElementsLod;
  29. };
  30. ShadowMapping::~ShadowMapping()
  31. {
  32. }
  33. Error ShadowMapping::init()
  34. {
  35. const Error err = initInternal();
  36. if(err)
  37. {
  38. ANKI_R_LOGE("Failed to initialize shadowmapping");
  39. }
  40. return err;
  41. }
  42. Error ShadowMapping::initInternal()
  43. {
  44. // Init RT
  45. {
  46. m_tileResolution = ConfigSet::getSingleton().getRShadowMappingTileResolution();
  47. m_tileCountBothAxis = ConfigSet::getSingleton().getRShadowMappingTileCountPerRowOrColumn();
  48. ANKI_R_LOGV("Initializing shadowmapping. Atlas resolution %ux%u", m_tileResolution * m_tileCountBothAxis,
  49. m_tileResolution * m_tileCountBothAxis);
  50. // RT
  51. const TextureUsageBit usage =
  52. TextureUsageBit::kSampledFragment | TextureUsageBit::kSampledCompute | TextureUsageBit::kAllFramebuffer;
  53. TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(m_tileResolution * m_tileCountBothAxis,
  54. m_tileResolution * m_tileCountBothAxis,
  55. Format::kD16_Unorm, usage, "ShadowAtlas");
  56. ClearValue clearVal;
  57. clearVal.m_colorf[0] = 1.0f;
  58. m_atlasTex = m_r->createAndClearRenderTarget(texinit, TextureUsageBit::kSampledFragment, clearVal);
  59. }
  60. // Tiles
  61. m_tileAlloc.init(&getMemoryPool(), m_tileCountBothAxis, m_tileCountBothAxis, kTileAllocHierarchyCount, true);
  62. m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
  63. m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kLoad;
  64. m_fbDescr.bake();
  65. ANKI_CHECK(getExternalSubsystems().m_resourceManager->loadResource(
  66. "ShaderBinaries/ShadowmappingClearDepth.ankiprogbin", m_clearDepthProg));
  67. const ShaderProgramResourceVariant* variant;
  68. m_clearDepthProg->getOrCreateVariant(variant);
  69. m_clearDepthGrProg = variant->getProgram();
  70. return Error::kNone;
  71. }
  72. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  73. {
  74. ANKI_TRACE_SCOPED_EVENT(RSm);
  75. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  76. // Import
  77. if(m_rtImportedOnce) [[likely]]
  78. {
  79. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex);
  80. }
  81. else
  82. {
  83. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex, TextureUsageBit::kSampledFragment);
  84. m_rtImportedOnce = true;
  85. }
  86. // First process the lights
  87. U32 threadCountForPass = 0;
  88. processLights(ctx, threadCountForPass);
  89. // Build the render graph
  90. if(m_runCtx.m_workItems.getSize())
  91. {
  92. // Will have to create render passes
  93. // Compute render area
  94. const U32 minx = m_runCtx.m_fullViewport[0];
  95. const U32 miny = m_runCtx.m_fullViewport[1];
  96. const U32 width = m_runCtx.m_fullViewport[2] - m_runCtx.m_fullViewport[0];
  97. const U32 height = m_runCtx.m_fullViewport[3] - m_runCtx.m_fullViewport[1];
  98. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("ShadowMapping");
  99. pass.setFramebufferInfo(m_fbDescr, {}, m_runCtx.m_rt, {}, minx, miny, width, height);
  100. ANKI_ASSERT(threadCountForPass && threadCountForPass <= CoreThreadHive::getSingleton().getThreadCount());
  101. pass.setWork(threadCountForPass, [this](RenderPassWorkContext& rgraphCtx) {
  102. runShadowMapping(rgraphCtx);
  103. });
  104. TextureSubresourceInfo subresource = TextureSubresourceInfo(DepthStencilAspectBit::kDepth);
  105. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kAllFramebuffer, subresource);
  106. pass.newBufferDependency(m_r->getGpuSceneBufferHandle(),
  107. BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
  108. }
  109. }
  110. Mat4 ShadowMapping::createSpotLightTextureMatrix(const UVec4& viewport) const
  111. {
  112. const F32 atlasSize = F32(m_tileResolution * m_tileCountBothAxis);
  113. #if ANKI_COMPILER_GCC_COMPATIBLE
  114. # pragma GCC diagnostic push
  115. # pragma GCC diagnostic ignored "-Wpedantic" // Because GCC and clang throw an incorrect warning
  116. #endif
  117. const Vec2 uv(F32(viewport[0]) / atlasSize, F32(viewport[1]) / atlasSize);
  118. #if ANKI_COMPILER_GCC_COMPATIBLE
  119. # pragma GCC diagnostic pop
  120. #endif
  121. ANKI_ASSERT(uv >= Vec2(0.0f) && uv <= Vec2(1.0f));
  122. ANKI_ASSERT(viewport[2] == viewport[3]);
  123. const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
  124. return Mat4(sizeTextureSpace, 0.0f, 0.0f, uv.x(), 0.0f, sizeTextureSpace, 0.0f, uv.y(), 0.0f, 0.0f, 1.0f, 0.0f,
  125. 0.0f, 0.0f, 0.0f, 1.0f);
  126. }
  127. void ShadowMapping::chooseDetail(const Vec4& cameraOrigin, const PointLightQueueElement& light,
  128. U32& tileAllocatorHierarchy, U32& renderQueueElementsLod) const
  129. {
  130. const F32 distFromTheCamera = (cameraOrigin - light.m_worldPosition.xyz0()).getLength() - light.m_radius;
  131. if(distFromTheCamera < ConfigSet::getSingleton().getLod0MaxDistance())
  132. {
  133. tileAllocatorHierarchy = kPointLightMaxTileAllocHierarchy;
  134. renderQueueElementsLod = 0;
  135. }
  136. else
  137. {
  138. tileAllocatorHierarchy = max(kPointLightMaxTileAllocHierarchy, 1u) - 1;
  139. renderQueueElementsLod = kMaxLodCount - 1;
  140. }
  141. }
  142. void ShadowMapping::chooseDetail(const Vec4& cameraOrigin, const SpotLightQueueElement& light,
  143. U32& tileAllocatorHierarchy, U32& renderQueueElementsLod) const
  144. {
  145. // Get some data
  146. const Vec4 coneOrigin = light.m_worldTransform.getTranslationPart().xyz0();
  147. const Vec4 coneDir = -light.m_worldTransform.getZAxis().xyz0();
  148. const F32 coneAngle = light.m_outerAngle;
  149. // Compute the distance from the camera to the light cone
  150. const Vec4 V = cameraOrigin - coneOrigin;
  151. const F32 VlenSq = V.dot(V);
  152. const F32 V1len = V.dot(coneDir);
  153. const F32 distFromTheCamera = cos(coneAngle) * sqrt(VlenSq - V1len * V1len) - V1len * sin(coneAngle);
  154. if(distFromTheCamera < ConfigSet::getSingleton().getLod0MaxDistance())
  155. {
  156. tileAllocatorHierarchy = kSpotLightMaxTileAllocHierarchy;
  157. renderQueueElementsLod = 0;
  158. }
  159. else if(distFromTheCamera < ConfigSet::getSingleton().getLod1MaxDistance())
  160. {
  161. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 1u) - 1;
  162. renderQueueElementsLod = kMaxLodCount - 1;
  163. }
  164. else
  165. {
  166. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 2u) - 2;
  167. renderQueueElementsLod = kMaxLodCount - 1;
  168. }
  169. }
  170. Bool ShadowMapping::allocateAtlasTiles(U64 lightUuid, U32 faceCount, const U64* faceTimestamps, const U32* faceIndices,
  171. const U32* drawcallsCount, const U32* hierarchies, UVec4* atlasTileViewports,
  172. TileAllocatorResult* subResults)
  173. {
  174. ANKI_ASSERT(lightUuid > 0);
  175. ANKI_ASSERT(faceCount > 0);
  176. ANKI_ASSERT(faceTimestamps);
  177. ANKI_ASSERT(faceIndices);
  178. ANKI_ASSERT(drawcallsCount);
  179. ANKI_ASSERT(hierarchies);
  180. for(U i = 0; i < faceCount; ++i)
  181. {
  182. Array<U32, 4> tileViewport;
  183. subResults[i] = m_tileAlloc.allocate(*getExternalSubsystems().m_globTimestamp, faceTimestamps[i], lightUuid,
  184. faceIndices[i], drawcallsCount[i], hierarchies[i], tileViewport);
  185. if(subResults[i] == TileAllocatorResult::kAllocationFailed)
  186. {
  187. ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. "
  188. "Increase the RShadowMappingTileCountPerRowOrColumn or decrease the scene's shadow casters");
  189. // Invalidate cache entries for what we already allocated
  190. for(U j = 0; j < i; ++j)
  191. {
  192. m_tileAlloc.invalidateCache(lightUuid, faceIndices[j]);
  193. }
  194. return false;
  195. }
  196. // Set viewport
  197. const UVec4 viewport = UVec4(tileViewport) * m_tileResolution;
  198. atlasTileViewports[i] = viewport;
  199. m_runCtx.m_fullViewport[0] = min(m_runCtx.m_fullViewport[0], viewport[0]);
  200. m_runCtx.m_fullViewport[1] = min(m_runCtx.m_fullViewport[1], viewport[1]);
  201. m_runCtx.m_fullViewport[2] = max(m_runCtx.m_fullViewport[2], viewport[0] + viewport[2]);
  202. m_runCtx.m_fullViewport[3] = max(m_runCtx.m_fullViewport[3], viewport[1] + viewport[3]);
  203. }
  204. return true;
  205. }
  206. void ShadowMapping::newWorkItems(const UVec4& atlasViewport, RenderQueue* lightRenderQueue, U32 renderQueueElementsLod,
  207. DynamicArrayRaii<LightToRenderTempInfo>& workItems, U32& drawcallCount) const
  208. {
  209. LightToRenderTempInfo toRender;
  210. toRender.m_renderQueue = lightRenderQueue;
  211. toRender.m_viewport = atlasViewport;
  212. toRender.m_drawcallCount = lightRenderQueue->m_renderables.getSize();
  213. toRender.m_renderQueueElementsLod = renderQueueElementsLod;
  214. workItems.emplaceBack(toRender);
  215. drawcallCount += toRender.m_drawcallCount;
  216. }
  217. void ShadowMapping::processLights(RenderingContext& ctx, U32& threadCountForPass)
  218. {
  219. m_runCtx.m_fullViewport = UVec4(kMaxU32, kMaxU32, kMinU32, kMinU32);
  220. // Vars
  221. const Vec4 cameraOrigin = ctx.m_renderQueue->m_cameraTransform.getTranslationPart().xyz0();
  222. DynamicArrayRaii<LightToRenderTempInfo> lightsToRender(ctx.m_tempPool);
  223. U32 drawcallCount = 0;
  224. // First thing, allocate an empty tile for empty faces of point lights
  225. UVec4 emptyTileViewport;
  226. {
  227. Array<U32, 4> tileViewport;
  228. [[maybe_unused]] const TileAllocatorResult res = m_tileAlloc.allocate(
  229. *getExternalSubsystems().m_globTimestamp, 1, kMaxU64, 0, 1, kPointLightMaxTileAllocHierarchy, tileViewport);
  230. emptyTileViewport = UVec4(tileViewport);
  231. #if ANKI_ENABLE_ASSERTIONS
  232. static Bool firstRun = true;
  233. if(firstRun)
  234. {
  235. ANKI_ASSERT(res == TileAllocatorResult::kAllocationSucceded);
  236. firstRun = false;
  237. }
  238. else
  239. {
  240. ANKI_ASSERT(res == TileAllocatorResult::kCached);
  241. }
  242. #endif
  243. }
  244. // Process the directional light first.
  245. if(ctx.m_renderQueue->m_directionalLight.m_shadowCascadeCount > 0)
  246. {
  247. DirectionalLightQueueElement& light = ctx.m_renderQueue->m_directionalLight;
  248. Array<U64, kMaxShadowCascades> timestamps;
  249. Array<U32, kMaxShadowCascades> cascadeIndices;
  250. Array<U32, kMaxShadowCascades> drawcallCounts;
  251. Array<UVec4, kMaxShadowCascades> atlasViewports;
  252. Array<TileAllocatorResult, kMaxShadowCascades> subResults;
  253. Array<U32, kMaxShadowCascades> hierarchies;
  254. Array<U32, kMaxShadowCascades> renderQueueElementsLods;
  255. U32 activeCascades = 0;
  256. for(U32 cascade = 0; cascade < light.m_shadowCascadeCount; ++cascade)
  257. {
  258. ANKI_ASSERT(light.m_shadowRenderQueues[cascade]);
  259. if(light.m_shadowRenderQueues[cascade]->m_renderables.getSize() > 0)
  260. {
  261. // Cascade with drawcalls, will need tiles
  262. timestamps[activeCascades] = *getExternalSubsystems().m_globTimestamp; // This light is always updated
  263. cascadeIndices[activeCascades] = cascade;
  264. drawcallCounts[activeCascades] = 1; // Doesn't matter
  265. // Change the quality per cascade
  266. hierarchies[activeCascades] =
  267. (cascade <= 1) ? (kTileAllocHierarchyCount - 1) : (kTileAllocHierarchyCount - 2);
  268. renderQueueElementsLods[activeCascades] = (cascade == 0) ? 0 : (kMaxLodCount - 1);
  269. ++activeCascades;
  270. }
  271. }
  272. const Bool allocationFailed =
  273. activeCascades == 0
  274. || !allocateAtlasTiles(light.m_uuid, activeCascades, &timestamps[0], &cascadeIndices[0], &drawcallCounts[0],
  275. &hierarchies[0], &atlasViewports[0], &subResults[0]);
  276. if(!allocationFailed)
  277. {
  278. activeCascades = 0;
  279. for(U cascade = 0; cascade < light.m_shadowCascadeCount; ++cascade)
  280. {
  281. if(light.m_shadowRenderQueues[cascade]->m_renderables.getSize() > 0)
  282. {
  283. // Cascade with drawcalls, push some work for it
  284. // Update the texture matrix to point to the correct region in the atlas
  285. light.m_textureMatrices[cascade] =
  286. createSpotLightTextureMatrix(atlasViewports[activeCascades]) * light.m_textureMatrices[cascade];
  287. // Push work
  288. newWorkItems(atlasViewports[activeCascades], light.m_shadowRenderQueues[cascade],
  289. renderQueueElementsLods[activeCascades], lightsToRender, drawcallCount);
  290. ++activeCascades;
  291. }
  292. else
  293. {
  294. // Empty cascade, point it to the empty tile
  295. light.m_textureMatrices[cascade] =
  296. createSpotLightTextureMatrix(emptyTileViewport) * light.m_textureMatrices[cascade];
  297. }
  298. }
  299. }
  300. else
  301. {
  302. // Light can't be a caster this frame
  303. light.m_shadowCascadeCount = 0;
  304. zeroMemory(light.m_shadowRenderQueues);
  305. }
  306. }
  307. // Process the point lights.
  308. for(PointLightQueueElement& light : ctx.m_renderQueue->m_pointLights)
  309. {
  310. if(!light.hasShadow())
  311. {
  312. continue;
  313. }
  314. // Prepare data to allocate tiles and allocate
  315. Array<U64, 6> timestamps;
  316. Array<U32, 6> faceIndices;
  317. Array<U32, 6> drawcallCounts;
  318. Array<UVec4, 6> atlasViewports;
  319. Array<TileAllocatorResult, 6> subResults;
  320. Array<U32, 6> hierarchies;
  321. U32 numOfFacesThatHaveDrawcalls = 0;
  322. U32 hierarchy, renderQueueElementsLod;
  323. chooseDetail(cameraOrigin, light, hierarchy, renderQueueElementsLod);
  324. for(U32 face = 0; face < 6; ++face)
  325. {
  326. ANKI_ASSERT(light.m_shadowRenderQueues[face]);
  327. if(light.m_shadowRenderQueues[face]->m_renderables.getSize())
  328. {
  329. // Has renderables, need to allocate tiles for it so add it to the arrays
  330. faceIndices[numOfFacesThatHaveDrawcalls] = face;
  331. timestamps[numOfFacesThatHaveDrawcalls] =
  332. light.m_shadowRenderQueues[face]->m_shadowRenderablesLastUpdateTimestamp;
  333. drawcallCounts[numOfFacesThatHaveDrawcalls] = light.m_shadowRenderQueues[face]->m_renderables.getSize();
  334. hierarchies[numOfFacesThatHaveDrawcalls] = hierarchy;
  335. ++numOfFacesThatHaveDrawcalls;
  336. }
  337. }
  338. const Bool allocationFailed =
  339. numOfFacesThatHaveDrawcalls == 0
  340. || !allocateAtlasTiles(light.m_uuid, numOfFacesThatHaveDrawcalls, &timestamps[0], &faceIndices[0],
  341. &drawcallCounts[0], &hierarchies[0], &atlasViewports[0], &subResults[0]);
  342. if(!allocationFailed)
  343. {
  344. // All good, update the lights
  345. // Remove a few texels to avoid bilinear filtering bleeding
  346. F32 texelsBorder;
  347. if(ConfigSet::getSingleton().getRShadowMappingPcf())
  348. {
  349. texelsBorder = 2.0f; // 2 texels
  350. }
  351. else
  352. {
  353. texelsBorder = 0.5f; // Half texel
  354. }
  355. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  356. F32 superTileSize = F32(atlasViewports[0][2]); // Should be the same for all tiles and faces
  357. superTileSize -= texelsBorder * 2.0f; // Remove from both sides
  358. light.m_shadowAtlasTileSize = superTileSize / atlasResolution;
  359. numOfFacesThatHaveDrawcalls = 0;
  360. for(U face = 0; face < 6; ++face)
  361. {
  362. if(light.m_shadowRenderQueues[face]->m_renderables.getSize())
  363. {
  364. // Has drawcalls, asigned it to a tile
  365. const UVec4& atlasViewport = atlasViewports[numOfFacesThatHaveDrawcalls];
  366. // Add a half texel to the viewport's start to avoid bilinear filtering bleeding
  367. light.m_shadowAtlasTileOffsets[face].x() = (F32(atlasViewport[0]) + texelsBorder) / atlasResolution;
  368. light.m_shadowAtlasTileOffsets[face].y() = (F32(atlasViewport[1]) + texelsBorder) / atlasResolution;
  369. if(subResults[numOfFacesThatHaveDrawcalls] != TileAllocatorResult::kCached)
  370. {
  371. newWorkItems(atlasViewport, light.m_shadowRenderQueues[face], renderQueueElementsLod,
  372. lightsToRender, drawcallCount);
  373. }
  374. ++numOfFacesThatHaveDrawcalls;
  375. }
  376. else
  377. {
  378. // Doesn't have renderables, point the face to the empty tile
  379. UVec4 atlasViewport = emptyTileViewport;
  380. ANKI_ASSERT(F32(atlasViewport[2]) <= superTileSize && F32(atlasViewport[3]) <= superTileSize);
  381. atlasViewport[2] = U32(superTileSize);
  382. atlasViewport[3] = U32(superTileSize);
  383. light.m_shadowAtlasTileOffsets[face].x() = (F32(atlasViewport[0]) + texelsBorder) / atlasResolution;
  384. light.m_shadowAtlasTileOffsets[face].y() = (F32(atlasViewport[1]) + texelsBorder) / atlasResolution;
  385. }
  386. }
  387. }
  388. else
  389. {
  390. // Light can't be a caster this frame
  391. zeroMemory(light.m_shadowRenderQueues);
  392. }
  393. }
  394. // Process the spot lights
  395. for(SpotLightQueueElement& light : ctx.m_renderQueue->m_spotLights)
  396. {
  397. if(!light.hasShadow())
  398. {
  399. continue;
  400. }
  401. // Allocate tiles
  402. U32 faceIdx = 0;
  403. TileAllocatorResult subResult = TileAllocatorResult::kAllocationFailed;
  404. UVec4 atlasViewport;
  405. UVec4 scratchViewport;
  406. const U32 localDrawcallCount = light.m_shadowRenderQueue->m_renderables.getSize();
  407. U32 hierarchy, renderQueueElementsLod;
  408. chooseDetail(cameraOrigin, light, hierarchy, renderQueueElementsLod);
  409. const Bool allocationFailed =
  410. localDrawcallCount == 0
  411. || !allocateAtlasTiles(light.m_uuid, 1, &light.m_shadowRenderQueue->m_shadowRenderablesLastUpdateTimestamp,
  412. &faceIdx, &localDrawcallCount, &hierarchy, &atlasViewport, &subResult);
  413. if(!allocationFailed)
  414. {
  415. // All good, update the light
  416. // Update the texture matrix to point to the correct region in the atlas
  417. light.m_textureMatrix = createSpotLightTextureMatrix(atlasViewport) * light.m_textureMatrix;
  418. if(subResult != TileAllocatorResult::kCached)
  419. {
  420. newWorkItems(atlasViewport, light.m_shadowRenderQueue, renderQueueElementsLod, lightsToRender,
  421. drawcallCount);
  422. }
  423. }
  424. else
  425. {
  426. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  427. light.m_shadowRenderQueue = nullptr;
  428. }
  429. }
  430. // Split the work that will happen in the scratch buffer
  431. if(lightsToRender.getSize())
  432. {
  433. DynamicArrayRaii<ThreadWorkItem> workItems(ctx.m_tempPool);
  434. LightToRenderTempInfo* lightToRender = lightsToRender.getBegin();
  435. U32 lightToRenderDrawcallCount = lightToRender->m_drawcallCount;
  436. const LightToRenderTempInfo* lightToRenderEnd = lightsToRender.getEnd();
  437. const U32 threadCount = computeNumberOfSecondLevelCommandBuffers(drawcallCount);
  438. threadCountForPass = threadCount;
  439. for(U32 taskId = 0; taskId < threadCount; ++taskId)
  440. {
  441. U32 start, end;
  442. splitThreadedProblem(taskId, threadCount, drawcallCount, start, end);
  443. // While there are drawcalls in this task emit new work items
  444. U32 taskDrawcallCount = end - start;
  445. ANKI_ASSERT(taskDrawcallCount > 0 && "Because we used computeNumberOfSecondLevelCommandBuffers()");
  446. while(taskDrawcallCount)
  447. {
  448. ANKI_ASSERT(lightToRender != lightToRenderEnd);
  449. const U32 workItemDrawcallCount = min(lightToRenderDrawcallCount, taskDrawcallCount);
  450. ThreadWorkItem workItem;
  451. workItem.m_viewport = lightToRender->m_viewport;
  452. workItem.m_renderQueue = lightToRender->m_renderQueue;
  453. workItem.m_firstRenderableElement = lightToRender->m_drawcallCount - lightToRenderDrawcallCount;
  454. workItem.m_renderableElementCount = workItemDrawcallCount;
  455. workItem.m_threadPoolTaskIdx = taskId;
  456. workItem.m_renderQueueElementsLod = lightToRender->m_renderQueueElementsLod;
  457. workItems.emplaceBack(workItem);
  458. // Decrease the drawcall counts for the task and the light
  459. ANKI_ASSERT(taskDrawcallCount >= workItemDrawcallCount);
  460. taskDrawcallCount -= workItemDrawcallCount;
  461. ANKI_ASSERT(lightToRenderDrawcallCount >= workItemDrawcallCount);
  462. lightToRenderDrawcallCount -= workItemDrawcallCount;
  463. // Move to the next light
  464. if(lightToRenderDrawcallCount == 0)
  465. {
  466. ++lightToRender;
  467. lightToRenderDrawcallCount =
  468. (lightToRender != lightToRenderEnd) ? lightToRender->m_drawcallCount : 0;
  469. }
  470. }
  471. }
  472. ANKI_ASSERT(lightToRender == lightToRenderEnd);
  473. ANKI_ASSERT(lightsToRender.getSize() <= workItems.getSize());
  474. // All good, store the work items for the threads to pick up
  475. workItems.moveAndReset(m_runCtx.m_workItems);
  476. }
  477. else
  478. {
  479. m_runCtx.m_workItems = {};
  480. }
  481. }
  482. void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  483. {
  484. ANKI_ASSERT(m_runCtx.m_workItems.getSize());
  485. ANKI_TRACE_SCOPED_EVENT(RSm);
  486. CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
  487. const U threadIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
  488. cmdb->setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  489. for(ThreadWorkItem& work : m_runCtx.m_workItems)
  490. {
  491. if(work.m_threadPoolTaskIdx != threadIdx)
  492. {
  493. continue;
  494. }
  495. // Set state
  496. cmdb->setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  497. cmdb->setScissor(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  498. // The 1st drawcall will clear the depth buffer
  499. if(work.m_firstRenderableElement == 0)
  500. {
  501. cmdb->bindShaderProgram(m_clearDepthGrProg);
  502. cmdb->setDepthCompareOperation(CompareOperation::kAlways);
  503. cmdb->setPolygonOffset(0.0f, 0.0f);
  504. cmdb->drawArrays(PrimitiveTopology::kTriangles, 3, 1);
  505. // Restore state
  506. cmdb->setDepthCompareOperation(CompareOperation::kLess);
  507. cmdb->setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  508. }
  509. RenderableDrawerArguments args;
  510. args.m_viewMatrix = work.m_renderQueue->m_viewMatrix;
  511. args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
  512. args.m_viewProjectionMatrix = work.m_renderQueue->m_viewProjectionMatrix;
  513. args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
  514. args.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
  515. m_r->getSceneDrawer().drawRange(args,
  516. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement,
  517. work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement
  518. + work.m_renderableElementCount,
  519. cmdb);
  520. }
  521. }
  522. } // end namespace anki