ShadowMapping.cpp 25 KB

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