ShadowMapping.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  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/GBuffer.h>
  8. #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
  9. #include <AnKi/Core/App.h>
  10. #include <AnKi/Core/StatsSet.h>
  11. #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
  12. #include <AnKi/Util/ThreadHive.h>
  13. #include <AnKi/Util/Tracer.h>
  14. #include <AnKi/Scene/Components/LightComponent.h>
  15. #include <AnKi/Scene/Components/CameraComponent.h>
  16. #include <AnKi/Scene/RenderStateBucket.h>
  17. namespace anki {
  18. static NumericCVar<U32> g_shadowMappingTileResolutionCVar(CVarSubsystem::kRenderer, "ShadowMappingTileResolution", (ANKI_PLATFORM_MOBILE) ? 128 : 256,
  19. 16, 2048, "Shadowmapping tile resolution");
  20. static NumericCVar<U32> g_shadowMappingTileCountPerRowOrColumnCVar(CVarSubsystem::kRenderer, "ShadowMappingTileCountPerRowOrColumn", 32, 1, 256,
  21. "Shadowmapping atlas will have this number squared number of tiles");
  22. NumericCVar<U32> g_shadowMappingPcfCVar(CVarSubsystem::kRenderer, "ShadowMappingPcf", (ANKI_PLATFORM_MOBILE) ? 0 : 1, 0, 1,
  23. "Shadow PCF (CVarSubsystem::kRenderer, 0: off, 1: on)");
  24. static StatCounter g_tilesAllocatedStatVar(StatCategory::kRenderer, "Shadow tiles (re)allocated", StatFlag::kMainThreadUpdates);
  25. class LightHash
  26. {
  27. public:
  28. class Unpacked
  29. {
  30. public:
  31. U64 m_uuid : 31;
  32. U64 m_componentIndex : 30;
  33. U64 m_faceIdx : 3;
  34. };
  35. union
  36. {
  37. Unpacked m_unpacked;
  38. U64 m_packed;
  39. };
  40. };
  41. static U64 encodeTileHash(U32 lightUuid, U32 componentIndex, U32 faceIdx)
  42. {
  43. ANKI_ASSERT(faceIdx < 6);
  44. LightHash c;
  45. c.m_unpacked.m_uuid = lightUuid;
  46. c.m_unpacked.m_componentIndex = componentIndex;
  47. c.m_unpacked.m_faceIdx = faceIdx;
  48. return c.m_packed;
  49. }
  50. static LightHash decodeTileHash(U64 hash)
  51. {
  52. LightHash c;
  53. c.m_packed = hash;
  54. return c;
  55. }
  56. class ShadowMapping::ViewportWorkItem
  57. {
  58. public:
  59. UVec4 m_viewport;
  60. Mat4 m_viewProjMat;
  61. Mat3x4 m_viewMat;
  62. GpuVisibilityOutput m_visOut;
  63. BufferOffsetRange m_clearTileIndirectArgs;
  64. };
  65. Error ShadowMapping::init()
  66. {
  67. const Error err = initInternal();
  68. if(err)
  69. {
  70. ANKI_R_LOGE("Failed to initialize shadowmapping");
  71. }
  72. return err;
  73. }
  74. Error ShadowMapping::initInternal()
  75. {
  76. // Init RT
  77. {
  78. m_tileResolution = g_shadowMappingTileResolutionCVar.get();
  79. m_tileCountBothAxis = g_shadowMappingTileCountPerRowOrColumnCVar.get();
  80. ANKI_R_LOGV("Initializing shadowmapping. Atlas resolution %ux%u", m_tileResolution * m_tileCountBothAxis,
  81. m_tileResolution * m_tileCountBothAxis);
  82. // RT
  83. const TextureUsageBit usage = TextureUsageBit::kSampledFragment | TextureUsageBit::kSampledCompute | TextureUsageBit::kAllFramebuffer;
  84. TextureInitInfo texinit = getRenderer().create2DRenderTargetInitInfo(
  85. m_tileResolution * m_tileCountBothAxis, m_tileResolution * m_tileCountBothAxis, Format::kD16_Unorm, usage, "ShadowAtlas");
  86. ClearValue clearVal;
  87. clearVal.m_colorf[0] = 1.0f;
  88. m_atlasTex = getRenderer().createAndClearRenderTarget(texinit, TextureUsageBit::kSampledFragment, clearVal);
  89. }
  90. // Tiles
  91. m_tileAlloc.init(m_tileCountBothAxis, m_tileCountBothAxis, kTileAllocHierarchyCount, true);
  92. m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
  93. m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kLoad;
  94. m_fbDescr.bake();
  95. ANKI_CHECK(loadShaderProgram("ShaderBinaries/ShadowMappingClearDepth.ankiprogbin", m_clearDepthProg, m_clearDepthGrProg));
  96. ANKI_CHECK(loadShaderProgram("ShaderBinaries/ShadowMappingVetVisibility.ankiprogbin", m_vetVisibilityProg, m_vetVisibilityGrProg));
  97. for(U32 i = 0; i < kMaxShadowCascades; ++i)
  98. {
  99. RendererString name;
  100. name.sprintf("DirLight HZB #%d", i);
  101. const U32 cascadeResolution = (m_tileResolution * (1 << (kTileAllocHierarchyCount - 1))) >> chooseDirectionalLightShadowCascadeDetail(i);
  102. UVec2 size(min(cascadeResolution, 1024u));
  103. size /= 2;
  104. m_cascadeHzbRtDescrs[i] = getRenderer().create2DRenderTargetDescription(size.x(), size.y(), Format::kR32_Sfloat, name);
  105. m_cascadeHzbRtDescrs[i].m_mipmapCount = U8(computeMaxMipmapCount2d(m_cascadeHzbRtDescrs[i].m_width, m_cascadeHzbRtDescrs[i].m_height));
  106. m_cascadeHzbRtDescrs[i].bake();
  107. }
  108. return Error::kNone;
  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. const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  125. return Mat4(sizeTextureSpace, 0.0f, 0.0f, uv.x(), 0.0f, sizeTextureSpace, 0.0f, uv.y(), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
  126. * biasMat4;
  127. }
  128. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  129. {
  130. ANKI_TRACE_SCOPED_EVENT(ShadowMapping);
  131. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  132. // Import
  133. if(m_rtImportedOnce) [[likely]]
  134. {
  135. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get());
  136. }
  137. else
  138. {
  139. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get(), TextureUsageBit::kSampledFragment);
  140. m_rtImportedOnce = true;
  141. }
  142. // First process the lights
  143. processLights(ctx);
  144. // Build the render graph
  145. if(m_runCtx.m_workItems.getSize())
  146. {
  147. // Will have to create render passes
  148. // Compute render area
  149. const U32 minx = m_runCtx.m_renderAreaMin.x();
  150. const U32 miny = m_runCtx.m_renderAreaMin.y();
  151. const U32 width = m_runCtx.m_renderAreaMax.x() - m_runCtx.m_renderAreaMin.x();
  152. const U32 height = m_runCtx.m_renderAreaMax.y() - m_runCtx.m_renderAreaMin.y();
  153. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Shadowmapping");
  154. for(const ViewportWorkItem& work : m_runCtx.m_workItems)
  155. {
  156. pass.newBufferDependency(work.m_visOut.m_someBufferHandle, BufferUsageBit::kIndirectDraw);
  157. }
  158. TextureSubresourceInfo subresource = TextureSubresourceInfo(DepthStencilAspectBit::kDepth);
  159. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kAllFramebuffer, subresource);
  160. pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
  161. BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
  162. pass.setFramebufferInfo(m_fbDescr, {}, m_runCtx.m_rt, {}, minx, miny, width, height);
  163. pass.setWork(1, [this](RenderPassWorkContext& rgraphCtx) {
  164. runShadowMapping(rgraphCtx);
  165. });
  166. }
  167. }
  168. void ShadowMapping::chooseDetail(const Vec3& cameraOrigin, const LightComponent& lightc, Vec2 lodDistances, U32& tileAllocatorHierarchy) const
  169. {
  170. if(lightc.getLightComponentType() == LightComponentType::kPoint)
  171. {
  172. const F32 distFromTheCamera = (cameraOrigin - lightc.getWorldPosition()).getLength() - lightc.getRadius();
  173. if(distFromTheCamera < lodDistances[0])
  174. {
  175. tileAllocatorHierarchy = kPointLightMaxTileAllocHierarchy;
  176. }
  177. else
  178. {
  179. tileAllocatorHierarchy = max(kPointLightMaxTileAllocHierarchy, 1u) - 1;
  180. }
  181. }
  182. else
  183. {
  184. ANKI_ASSERT(lightc.getLightComponentType() == LightComponentType::kSpot);
  185. // Get some data
  186. const Vec3 coneOrigin = lightc.getWorldPosition();
  187. const Vec3 coneDir = lightc.getDirection();
  188. const F32 coneAngle = lightc.getOuterAngle();
  189. // Compute the distance from the camera to the light cone
  190. const Vec3 V = cameraOrigin - coneOrigin;
  191. const F32 VlenSq = V.dot(V);
  192. const F32 V1len = V.dot(coneDir);
  193. const F32 distFromTheCamera = cos(coneAngle) * sqrt(VlenSq - V1len * V1len) - V1len * sin(coneAngle);
  194. if(distFromTheCamera < lodDistances[0])
  195. {
  196. tileAllocatorHierarchy = kSpotLightMaxTileAllocHierarchy;
  197. }
  198. else if(distFromTheCamera < lodDistances[1])
  199. {
  200. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 1u) - 1;
  201. }
  202. else
  203. {
  204. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 2u) - 2;
  205. }
  206. }
  207. }
  208. TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies,
  209. UVec4* atlasTileViewports)
  210. {
  211. ANKI_ASSERT(lightUuid > 0);
  212. ANKI_ASSERT(faceCount > 0);
  213. ANKI_ASSERT(hierarchies);
  214. TileAllocatorResult2 goodResult = TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached;
  215. for(U32 i = 0; i < faceCount; ++i)
  216. {
  217. TileAllocator::ArrayOfLightUuids kickedOutLights(&getRenderer().getFrameMemoryPool());
  218. Array<U32, 4> tileViewport;
  219. const TileAllocatorResult2 result = m_tileAlloc.allocate(
  220. GlobalFrameIndex::getSingleton().m_value, encodeTileHash(lightUuid, componentIndex, i), hierarchies[i], tileViewport, kickedOutLights);
  221. for(U64 kickedLightHash : kickedOutLights)
  222. {
  223. const LightHash hash = decodeTileHash(kickedLightHash);
  224. const Bool found = SceneGraph::getSingleton().getComponentArrays().getLights().indexExists(hash.m_unpacked.m_componentIndex);
  225. if(found)
  226. {
  227. LightComponent& lightc = SceneGraph::getSingleton().getComponentArrays().getLights()[hash.m_unpacked.m_componentIndex];
  228. if(lightc.getUuid() == hash.m_unpacked.m_uuid)
  229. {
  230. lightc.setShadowAtlasUvViewports({});
  231. }
  232. }
  233. }
  234. if(!!(result & TileAllocatorResult2::kAllocationFailed))
  235. {
  236. ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. Increase the %s or decrease the scene's shadow casters",
  237. g_shadowMappingTileCountPerRowOrColumnCVar.getFullName().cstr());
  238. // Invalidate cache entries for what we already allocated
  239. for(U32 j = 0; j < i; ++j)
  240. {
  241. m_tileAlloc.invalidateCache(encodeTileHash(lightUuid, componentIndex, j));
  242. }
  243. return TileAllocatorResult2::kAllocationFailed;
  244. }
  245. if(!(result & TileAllocatorResult2::kTileCached))
  246. {
  247. g_tilesAllocatedStatVar.increment(1);
  248. }
  249. goodResult &= result;
  250. // Set viewport
  251. const UVec4 viewport = UVec4(tileViewport) * m_tileResolution;
  252. atlasTileViewports[i] = viewport;
  253. m_runCtx.m_renderAreaMin = m_runCtx.m_renderAreaMin.min(UVec2(viewport[0], viewport[1]));
  254. m_runCtx.m_renderAreaMax = m_runCtx.m_renderAreaMax.max(UVec2(viewport[0] + viewport[2], viewport[1] + viewport[3]));
  255. }
  256. return goodResult;
  257. }
  258. void ShadowMapping::processLights(RenderingContext& ctx)
  259. {
  260. m_runCtx.m_renderAreaMin = UVec2(kMaxU32, kMaxU32);
  261. m_runCtx.m_renderAreaMax = UVec2(kMinU32, kMinU32);
  262. // Vars
  263. const Vec3 cameraOrigin = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  264. DynamicArray<ViewportWorkItem, MemoryPoolPtrWrapper<StackMemoryPool>> workItems(&getRenderer().getFrameMemoryPool());
  265. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  266. const CameraComponent& mainCam = SceneGraph::getSingleton().getActiveCameraNode().getFirstComponentOfType<CameraComponent>();
  267. // Process the directional light first.
  268. const LightComponent* dirLight = SceneGraph::getSingleton().getDirectionalLight();
  269. if(dirLight && dirLight->getShadowEnabled() && g_shadowCascadeCountCVar.get())
  270. {
  271. const U32 cascadeCount = g_shadowCascadeCountCVar.get();
  272. Array<U32, kMaxShadowCascades> cascadeIndices;
  273. Array<U32, kMaxShadowCascades> hierarchies;
  274. for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
  275. {
  276. cascadeIndices[cascade] = cascade;
  277. // Change the quality per cascade
  278. hierarchies[cascade] = kTileAllocHierarchyCount - 1 - chooseDirectionalLightShadowCascadeDetail(cascade);
  279. }
  280. Array<UVec4, kMaxShadowCascades> atlasViewports;
  281. [[maybe_unused]] const TileAllocatorResult2 res = allocateAtlasTiles(kMaxU32, 0, cascadeCount, &hierarchies[0], &atlasViewports[0]);
  282. ANKI_ASSERT(!!(res & TileAllocatorResult2::kAllocationSucceded) && "Dir light should never fail");
  283. // Compute the view projection matrices
  284. Array<F32, kMaxShadowCascades> cascadeDistances;
  285. cascadeDistances[0] = g_shadowCascade0DistanceCVar.get();
  286. cascadeDistances[1] = g_shadowCascade1DistanceCVar.get();
  287. cascadeDistances[2] = g_shadowCascade2DistanceCVar.get();
  288. cascadeDistances[3] = g_shadowCascade3DistanceCVar.get();
  289. Array<Mat4, kMaxShadowCascades> cascadeViewProjMats;
  290. Array<Mat3x4, kMaxShadowCascades> cascadeViewMats;
  291. Array<Mat4, kMaxShadowCascades> cascadeProjMats;
  292. dirLight->computeCascadeFrustums(mainCam.getFrustum(), {&cascadeDistances[0], cascadeCount}, {&cascadeProjMats[0], cascadeCount},
  293. {&cascadeViewMats[0], cascadeCount});
  294. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  295. {
  296. cascadeViewProjMats[cascade] = cascadeProjMats[cascade] * Mat4(cascadeViewMats[cascade], Vec4(0.0f, 0.0f, 0.0f, 1.0f));
  297. }
  298. // HZB generation
  299. HzbDirectionalLightInput hzbGenIn;
  300. hzbGenIn.m_cascadeCount = cascadeCount;
  301. hzbGenIn.m_depthBufferRt = getRenderer().getGBuffer().getDepthRt();
  302. hzbGenIn.m_depthBufferRtSize = getRenderer().getInternalResolution();
  303. hzbGenIn.m_cameraInverseViewProjectionMatrix = ctx.m_matrices.m_invertedViewProjection;
  304. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  305. {
  306. hzbGenIn.m_cascades[cascade].m_hzbRt = rgraph.newRenderTarget(m_cascadeHzbRtDescrs[cascade]);
  307. hzbGenIn.m_cascades[cascade].m_hzbRtSize = UVec2(m_cascadeHzbRtDescrs[cascade].m_width, m_cascadeHzbRtDescrs[cascade].m_height);
  308. hzbGenIn.m_cascades[cascade].m_viewMatrix = cascadeViewMats[cascade];
  309. hzbGenIn.m_cascades[cascade].m_projectionMatrix = cascadeProjMats[cascade];
  310. }
  311. getRenderer().getHzbGenerator().populateRenderGraphDirectionalLight(hzbGenIn, rgraph);
  312. // Vis testing
  313. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  314. {
  315. ViewportWorkItem& work = *workItems.emplaceBack();
  316. work.m_viewProjMat = cascadeViewProjMats[cascade];
  317. work.m_viewMat = cascadeViewMats[cascade];
  318. work.m_viewport = atlasViewports[cascade];
  319. // Vis testing
  320. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  321. FrustumGpuVisibilityInput visIn;
  322. visIn.m_passesName = "Shadows visibility: Dir light";
  323. visIn.m_technique = RenderingTechnique::kDepth;
  324. visIn.m_viewProjectionMatrix = cascadeViewProjMats[cascade];
  325. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  326. visIn.m_lodDistances = lodDistances;
  327. visIn.m_hzbRt = &hzbGenIn.m_cascades[cascade].m_hzbRt;
  328. visIn.m_rgraph = &rgraph;
  329. getRenderer().getGpuVisibility().populateRenderGraph(visIn, work.m_visOut);
  330. // Update the texture matrix to point to the correct region in the atlas
  331. ctx.m_dirLightTextureMatrices[cascade] = createSpotLightTextureMatrix(atlasViewports[cascade]) * cascadeViewProjMats[cascade];
  332. }
  333. }
  334. // Process the point lights.
  335. WeakArray<LightComponent*> lights = getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_shadowLights;
  336. for(LightComponent* lightc : lights)
  337. {
  338. if(lightc->getLightComponentType() != LightComponentType::kPoint || !lightc->getShadowEnabled())
  339. {
  340. continue;
  341. }
  342. // Prepare data to allocate tiles and allocate
  343. U32 hierarchy;
  344. chooseDetail(cameraOrigin, *lightc, {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()}, hierarchy);
  345. Array<U32, 6> hierarchies;
  346. hierarchies.fill(hierarchy);
  347. Array<UVec4, 6> atlasViewports;
  348. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 6, &hierarchies[0], &atlasViewports[0]);
  349. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  350. {
  351. // All good, update the light
  352. // Remove a few texels to avoid bilinear filtering bleeding
  353. F32 texelsBorder;
  354. if(g_shadowMappingPcfCVar.get())
  355. {
  356. texelsBorder = 2.0f; // 2 texels
  357. }
  358. else
  359. {
  360. texelsBorder = 0.5f; // Half texel
  361. }
  362. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  363. F32 superTileSize = F32(atlasViewports[0][2]); // Should be the same for all tiles and faces
  364. superTileSize -= texelsBorder * 2.0f; // Remove from both sides
  365. Array<Vec4, 6> uvViewports;
  366. for(U face = 0; face < 6; ++face)
  367. {
  368. // Add a half texel to the viewport's start to avoid bilinear filtering bleeding
  369. const Vec2 uvViewportXY = (Vec2(atlasViewports[face].xy()) + texelsBorder) / atlasResolution;
  370. uvViewports[face] = Vec4(uvViewportXY, Vec2(superTileSize / atlasResolution));
  371. }
  372. if(!(result & TileAllocatorResult2::kTileCached))
  373. {
  374. lightc->setShadowAtlasUvViewports(uvViewports);
  375. }
  376. // Vis testing
  377. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  378. DistanceGpuVisibilityInput visIn;
  379. visIn.m_passesName = "Shadows visibility: Point light";
  380. visIn.m_technique = RenderingTechnique::kDepth;
  381. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  382. visIn.m_lodDistances = lodDistances;
  383. visIn.m_rgraph = &rgraph;
  384. visIn.m_pointOfTest = lightc->getWorldPosition();
  385. visIn.m_testRadius = lightc->getRadius();
  386. visIn.m_hashVisibles = true;
  387. GpuVisibilityOutput visOut;
  388. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  389. // Vet visibility
  390. const Bool renderAllways = !(result & TileAllocatorResult2::kTileCached);
  391. BufferOffsetRange clearTileIndirectArgs;
  392. if(!renderAllways)
  393. {
  394. clearTileIndirectArgs = vetVisibilityPass("Shadows visibility: Vet point light", *lightc, visOut, rgraph);
  395. }
  396. // Add work
  397. for(U32 face = 0; face < 6; ++face)
  398. {
  399. Frustum frustum;
  400. frustum.init(FrustumType::kPerspective);
  401. frustum.setPerspective(kClusterObjectFrustumNearPlane, lightc->getRadius(), kPi / 2.0f, kPi / 2.0f);
  402. frustum.setWorldTransform(Transform(lightc->getWorldPosition().xyz0(), Frustum::getOmnidirectionalFrustumRotations()[face], 1.0f));
  403. frustum.update();
  404. ViewportWorkItem& work = *workItems.emplaceBack();
  405. work.m_viewProjMat = frustum.getViewProjectionMatrix();
  406. work.m_viewMat = frustum.getViewMatrix();
  407. work.m_viewport = atlasViewports[face];
  408. work.m_visOut = visOut;
  409. work.m_clearTileIndirectArgs = clearTileIndirectArgs;
  410. }
  411. }
  412. else
  413. {
  414. // Can't be a caster from now on
  415. lightc->setShadowAtlasUvViewports({});
  416. }
  417. }
  418. // Process the spot lights
  419. for(LightComponent* lightc : lights)
  420. {
  421. if(lightc->getLightComponentType() != LightComponentType::kSpot || !lightc->getShadowEnabled())
  422. {
  423. continue;
  424. }
  425. // Allocate tile
  426. U32 hierarchy;
  427. chooseDetail(cameraOrigin, *lightc, {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()}, hierarchy);
  428. UVec4 atlasViewport;
  429. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport);
  430. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  431. {
  432. // All good, update the light
  433. if(!(result & TileAllocatorResult2::kTileCached))
  434. {
  435. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  436. const Vec4 uvViewport = Vec4(atlasViewport) / atlasResolution;
  437. lightc->setShadowAtlasUvViewports({&uvViewport, 1});
  438. }
  439. // Vis testing
  440. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  441. FrustumGpuVisibilityInput visIn;
  442. visIn.m_passesName = "Shadows visibility: Spot light";
  443. visIn.m_technique = RenderingTechnique::kDepth;
  444. visIn.m_lodReferencePoint = cameraOrigin;
  445. visIn.m_lodDistances = lodDistances;
  446. visIn.m_rgraph = &rgraph;
  447. visIn.m_viewProjectionMatrix = lightc->getSpotLightViewProjectionMatrix();
  448. visIn.m_hashVisibles = true;
  449. GpuVisibilityOutput visOut;
  450. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  451. // Vet visibility
  452. const Bool renderAllways = !(result & TileAllocatorResult2::kTileCached);
  453. BufferOffsetRange clearTileIndirectArgs;
  454. if(!renderAllways)
  455. {
  456. clearTileIndirectArgs = vetVisibilityPass("Shadows visibility: Vet spot light", *lightc, visOut, rgraph);
  457. }
  458. // Add work
  459. ViewportWorkItem& work = *workItems.emplaceBack();
  460. work.m_viewProjMat = lightc->getSpotLightViewProjectionMatrix();
  461. work.m_viewMat = lightc->getSpotLightViewMatrix();
  462. work.m_viewport = atlasViewport;
  463. work.m_visOut = visOut;
  464. work.m_clearTileIndirectArgs = clearTileIndirectArgs;
  465. }
  466. else
  467. {
  468. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  469. lightc->setShadowAtlasUvViewports({});
  470. }
  471. }
  472. // Move the work to the context
  473. if(workItems.getSize())
  474. {
  475. // All good, store the work items for the threads to pick up
  476. workItems.moveAndReset(m_runCtx.m_workItems);
  477. }
  478. else
  479. {
  480. m_runCtx.m_workItems = {};
  481. }
  482. }
  483. void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  484. {
  485. ANKI_ASSERT(m_runCtx.m_workItems.getSize());
  486. ANKI_TRACE_SCOPED_EVENT(ShadowMapping);
  487. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  488. // Clear the depth buffer
  489. cmdb.bindShaderProgram(m_clearDepthGrProg.get());
  490. cmdb.setDepthCompareOperation(CompareOperation::kAlways);
  491. for(ViewportWorkItem& work : m_runCtx.m_workItems)
  492. {
  493. cmdb.setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  494. if(work.m_clearTileIndirectArgs.m_buffer)
  495. {
  496. cmdb.drawIndirect(PrimitiveTopology::kTriangles, 1, work.m_clearTileIndirectArgs.m_offset, work.m_clearTileIndirectArgs.m_buffer);
  497. }
  498. else
  499. {
  500. cmdb.draw(PrimitiveTopology::kTriangles, 3, 1);
  501. }
  502. }
  503. // Restore state
  504. cmdb.setDepthCompareOperation(CompareOperation::kLess);
  505. // Draw to tiles
  506. cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  507. for(ViewportWorkItem& work : m_runCtx.m_workItems)
  508. {
  509. // Set state
  510. cmdb.setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  511. cmdb.setScissor(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  512. RenderableDrawerArguments args;
  513. args.m_renderingTechinuqe = RenderingTechnique::kDepth;
  514. args.m_viewMatrix = work.m_viewMat;
  515. args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
  516. args.m_viewProjectionMatrix = work.m_viewProjMat;
  517. args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
  518. args.m_sampler = getRenderer().getSamplers().m_trilinearRepeatAniso.get();
  519. args.fillMdi(work.m_visOut);
  520. getRenderer().getSceneDrawer().drawMdi(args, cmdb);
  521. }
  522. }
  523. BufferOffsetRange ShadowMapping::vetVisibilityPass(CString passName, const LightComponent& lightc, const GpuVisibilityOutput& visOut,
  524. RenderGraphDescription& rgraph) const
  525. {
  526. BufferOffsetRange clearTileIndirectArgs;
  527. clearTileIndirectArgs = GpuVisibleTransientMemoryPool::getSingleton().allocate(sizeof(DrawIndirectArgs));
  528. ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(passName);
  529. // The shader doesn't actually write to the handle but have it as a write dependency for the drawer to correctly wait for this pass
  530. pass.newBufferDependency(visOut.m_someBufferHandle, BufferUsageBit::kStorageComputeWrite);
  531. pass.setWork([this, &lightc, hashBuff = visOut.m_visiblesHashBuffer, mdiBuff = visOut.m_mdiDrawCountsBuffer,
  532. clearTileIndirectArgs](RenderPassWorkContext& rpass) {
  533. CommandBuffer& cmdb = *rpass.m_commandBuffer;
  534. cmdb.bindShaderProgram(m_vetVisibilityGrProg.get());
  535. const UVec4 lightIndex(lightc.getGpuSceneLightAllocation().getIndex());
  536. cmdb.setPushConstants(&lightIndex, sizeof(lightIndex));
  537. cmdb.bindStorageBuffer(0, 0, hashBuff);
  538. cmdb.bindStorageBuffer(0, 1, mdiBuff);
  539. cmdb.bindStorageBuffer(0, 2, GpuSceneArrays::Light::getSingleton().getBufferOffsetRange());
  540. cmdb.bindStorageBuffer(0, 3, GpuSceneArrays::LightVisibleRenderablesHash::getSingleton().getBufferOffsetRange());
  541. cmdb.bindStorageBuffer(0, 4, clearTileIndirectArgs);
  542. ANKI_ASSERT(RenderStateBucketContainer::getSingleton().getBucketCount(RenderingTechnique::kDepth) <= 64 && "TODO");
  543. cmdb.dispatchCompute(1, 1, 1);
  544. });
  545. return clearTileIndirectArgs;
  546. }
  547. } // end namespace anki