Visibility.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  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/Scene/VisibilityInternal.h>
  6. #include <AnKi/Scene/SceneGraph.h>
  7. #include <AnKi/Scene/Components/LensFlareComponent.h>
  8. #include <AnKi/Scene/Components/ModelComponent.h>
  9. #include <AnKi/Scene/Components/ReflectionProbeComponent.h>
  10. #include <AnKi/Scene/Components/DecalComponent.h>
  11. #include <AnKi/Scene/Components/MoveComponent.h>
  12. #include <AnKi/Scene/Components/FogDensityComponent.h>
  13. #include <AnKi/Scene/Components/LightComponent.h>
  14. #include <AnKi/Scene/Components/GlobalIlluminationProbeComponent.h>
  15. #include <AnKi/Scene/Components/ParticleEmitterComponent.h>
  16. #include <AnKi/Scene/Components/UiComponent.h>
  17. #include <AnKi/Scene/Components/SkyboxComponent.h>
  18. #include <AnKi/Scene/Components/CameraComponent.h>
  19. #include <AnKi/Renderer/MainRenderer.h>
  20. #include <AnKi/Util/Logger.h>
  21. #include <AnKi/Util/ThreadHive.h>
  22. #include <AnKi/Core/ConfigSet.h>
  23. namespace anki {
  24. static U8 computeLod(const Frustum& frustum, F32 distanceFromTheNearPlane)
  25. {
  26. static_assert(kMaxLodCount == 3, "Wrong assumption");
  27. U8 lod;
  28. if(distanceFromTheNearPlane < 0.0f)
  29. {
  30. // In RT objects may fall behind the camera, use the max LOD on those
  31. lod = 2;
  32. }
  33. else if(distanceFromTheNearPlane <= frustum.getLodDistance(0))
  34. {
  35. lod = 0;
  36. }
  37. else if(distanceFromTheNearPlane <= frustum.getLodDistance(1))
  38. {
  39. lod = 1;
  40. }
  41. else
  42. {
  43. lod = 2;
  44. }
  45. return lod;
  46. }
  47. static FrustumFlags getLightFrustumFlags()
  48. {
  49. FrustumFlags flags;
  50. flags.m_gatherShadowCasterModelComponents = true;
  51. return flags;
  52. }
  53. static FrustumFlags getDirectionalLightFrustumFlags()
  54. {
  55. FrustumFlags flags;
  56. return flags;
  57. }
  58. static FrustumFlags getProbeFrustumFlags()
  59. {
  60. FrustumFlags flags;
  61. flags.m_gatherLightComponents = true;
  62. flags.m_gatherSkyComponents = true;
  63. flags.m_directionalLightsCastShadow = true;
  64. return flags;
  65. }
  66. static FrustumFlags getCameraFrustumFlags()
  67. {
  68. FrustumFlags flags;
  69. flags.m_gatherParticleComponents = true;
  70. flags.m_gatherProbeComponents = true;
  71. flags.m_gatherLightComponents = true;
  72. flags.m_gatherLensFlareComponents = true;
  73. flags.m_gatherDecalComponents = true;
  74. flags.m_gatherFogDensityComponents = true;
  75. flags.m_gatherUiComponents = true;
  76. flags.m_gatherSkyComponents = true;
  77. flags.m_coverageBuffer = true;
  78. flags.m_nonDirectionalLightsCastShadow = true;
  79. flags.m_directionalLightsCastShadow = true;
  80. return flags;
  81. }
  82. static FrustumFlags getCameraExtendedFrustumFlags()
  83. {
  84. FrustumFlags flags;
  85. flags.m_gatherRayTracingModelComponents = true;
  86. flags.m_gatherLightComponents = true;
  87. flags.m_gatherSkyComponents = true;
  88. return flags;
  89. }
  90. void VisibilityContext::submitNewWork(const VisibilityFrustum& frustum, const VisibilityFrustum& primaryFrustum, RenderQueue& rqueue,
  91. ThreadHive& hive)
  92. {
  93. ANKI_TRACE_SCOPED_EVENT(SceneVisSubmitWork);
  94. rqueue.m_cameraTransform = Mat3x4(frustum.m_frustum->getWorldTransform());
  95. rqueue.m_viewMatrix = frustum.m_frustum->getViewMatrix();
  96. rqueue.m_projectionMatrix = frustum.m_frustum->getProjectionMatrix();
  97. rqueue.m_viewProjectionMatrix = frustum.m_frustum->getViewProjectionMatrix();
  98. rqueue.m_previousViewProjectionMatrix = frustum.m_frustum->getPreviousViewProjectionMatrix();
  99. rqueue.m_cameraNear = frustum.m_frustum->getNear();
  100. rqueue.m_cameraFar = frustum.m_frustum->getFar();
  101. if(frustum.m_frustum->getFrustumType() == FrustumType::kPerspective)
  102. {
  103. rqueue.m_cameraFovX = frustum.m_frustum->getFovX();
  104. rqueue.m_cameraFovY = frustum.m_frustum->getFovY();
  105. }
  106. else
  107. {
  108. rqueue.m_cameraFovX = rqueue.m_cameraFovY = 0.0f;
  109. }
  110. // Check if this frc was tested before
  111. {
  112. LockGuard<Mutex> l(m_testedFrustumsMtx);
  113. // Check if already in the list
  114. for(const Frustum* x : m_testedFrustums)
  115. {
  116. if(x == frustum.m_frustum)
  117. {
  118. return;
  119. }
  120. }
  121. // Not there, push it
  122. m_testedFrustums.pushBack(frustum.m_frustum);
  123. }
  124. // Prepare the ctx
  125. FrustumVisibilityContext* frcCtx = newInstance<FrustumVisibilityContext>(SceneGraph::getSingleton().getFrameMemoryPool());
  126. frcCtx->m_visCtx = this;
  127. frcCtx->m_frustum = frustum;
  128. frcCtx->m_primaryFrustum = primaryFrustum;
  129. frcCtx->m_queueViews.resize(hive.getThreadCount());
  130. frcCtx->m_visTestsSignalSem = hive.newSemaphore(1);
  131. frcCtx->m_renderQueue = &rqueue;
  132. // Submit new work
  133. //
  134. // Software rasterizer task
  135. ThreadHiveSemaphore* prepareRasterizerSem = nullptr;
  136. if(frustum.m_coverageBuffer && frustum.m_frustum->hasCoverageBuffer())
  137. {
  138. // Gather triangles task
  139. ThreadHiveTask fillDepthTask = ANKI_THREAD_HIVE_TASK(
  140. { self->fill(); }, newInstance<FillRasterizerWithCoverageTask>(SceneGraph::getSingleton().getFrameMemoryPool(), frcCtx), nullptr,
  141. hive.newSemaphore(1));
  142. hive.submitTasks(&fillDepthTask, 1);
  143. prepareRasterizerSem = fillDepthTask.m_signalSemaphore;
  144. }
  145. if(frustum.m_coverageBuffer)
  146. {
  147. rqueue.m_fillCoverageBufferCallback = [](void* ud, F32* depthValues, U32 width, U32 height) {
  148. static_cast<Frustum*>(ud)->setCoverageBuffer(depthValues, width, height);
  149. };
  150. rqueue.m_fillCoverageBufferCallbackUserData = static_cast<Frustum*>(frustum.m_frustum);
  151. }
  152. // Gather visibles from the octree. No need to signal anything because it will spawn new tasks
  153. ThreadHiveTask gatherTask = ANKI_THREAD_HIVE_TASK(
  154. { self->gather(hive); }, newInstance<GatherVisiblesFromOctreeTask>(SceneGraph::getSingleton().getFrameMemoryPool(), frcCtx),
  155. prepareRasterizerSem, nullptr);
  156. hive.submitTasks(&gatherTask, 1);
  157. // Combind results task
  158. ANKI_ASSERT(frcCtx->m_visTestsSignalSem);
  159. ThreadHiveTask combineTask =
  160. ANKI_THREAD_HIVE_TASK({ self->combine(); }, newInstance<CombineResultsTask>(SceneGraph::getSingleton().getFrameMemoryPool(), frcCtx),
  161. frcCtx->m_visTestsSignalSem, nullptr);
  162. hive.submitTasks(&combineTask, 1);
  163. }
  164. void FillRasterizerWithCoverageTask::fill()
  165. {
  166. ANKI_TRACE_SCOPED_EVENT(SceneVisFillDepth);
  167. // Get the C-Buffer
  168. ConstWeakArray<F32> depthBuff;
  169. U32 width;
  170. U32 height;
  171. m_frcCtx->m_frustum.m_frustum->getCoverageBufferInfo(depthBuff, width, height);
  172. ANKI_ASSERT(width > 0 && height > 0 && depthBuff.getSize() > 0);
  173. // Init the rasterizer
  174. if(true)
  175. {
  176. m_frcCtx->m_r = newInstance<SoftwareRasterizer>(SceneGraph::getSingleton().getFrameMemoryPool());
  177. m_frcCtx->m_r->prepare(Mat4(m_frcCtx->m_frustum.m_frustum->getPreviousViewMatrix(1), Vec4(0.0f, 0.0f, 0.0f, 1.0f)),
  178. m_frcCtx->m_frustum.m_frustum->getPreviousProjectionMatrix(1), width, height);
  179. // Do the work
  180. m_frcCtx->m_r->fillDepthBuffer(depthBuff);
  181. }
  182. }
  183. void GatherVisiblesFromOctreeTask::gather(ThreadHive& hive)
  184. {
  185. ANKI_TRACE_SCOPED_EVENT(SceneVisOctreeGather);
  186. U32 testIdx = m_frcCtx->m_visCtx->m_testsCount.fetchAdd(1);
  187. // Walk the tree
  188. SceneGraph::getSingleton().getOctree().walkTree(
  189. testIdx,
  190. [&](const Aabb& box) {
  191. Bool visible = m_frcCtx->m_frustum.m_frustum->insideFrustum(box);
  192. if(visible && m_frcCtx->m_r)
  193. {
  194. // visible = m_frcCtx->m_r->visibilityTest(box);
  195. }
  196. return visible;
  197. },
  198. [&](void* placeableUserData) {
  199. ANKI_ASSERT(placeableUserData);
  200. Spatial* spatial = static_cast<Spatial*>(placeableUserData);
  201. const U8 compClassId = spatial->getSceneComponentClassId();
  202. const FrustumFlags frustumFlags = m_frcCtx->m_frustum;
  203. Bool gather = false;
  204. if(compClassId == ModelComponent::getStaticClassId())
  205. {
  206. gather = frustumFlags.m_gatherModelComponents || frustumFlags.m_gatherShadowCasterModelComponents
  207. || frustumFlags.m_gatherRayTracingModelComponents;
  208. }
  209. else if(compClassId == ParticleEmitterComponent::getStaticClassId())
  210. {
  211. gather = frustumFlags.m_gatherParticleComponents;
  212. }
  213. else if(compClassId == LightComponent::getStaticClassId())
  214. {
  215. gather = frustumFlags.m_gatherLightComponents;
  216. }
  217. else if(compClassId == LensFlareComponent::getStaticClassId())
  218. {
  219. gather = frustumFlags.m_gatherLensFlareComponents;
  220. }
  221. else if(compClassId == ReflectionProbeComponent::getStaticClassId())
  222. {
  223. gather = frustumFlags.m_gatherProbeComponents;
  224. }
  225. else if(compClassId == DecalComponent::getStaticClassId())
  226. {
  227. gather = frustumFlags.m_gatherDecalComponents;
  228. }
  229. else if(compClassId == FogDensityComponent::getStaticClassId())
  230. {
  231. gather = frustumFlags.m_gatherFogDensityComponents;
  232. }
  233. else if(compClassId == GlobalIlluminationProbeComponent::getStaticClassId())
  234. {
  235. gather = frustumFlags.m_gatherProbeComponents;
  236. }
  237. else if(compClassId == UiComponent::getStaticClassId())
  238. {
  239. gather = frustumFlags.m_gatherUiComponents;
  240. }
  241. else if(compClassId == SkyboxComponent::getStaticClassId())
  242. {
  243. gather = frustumFlags.m_gatherSkyComponents;
  244. }
  245. else
  246. {
  247. ANKI_ASSERT(0);
  248. }
  249. if(!gather)
  250. {
  251. return;
  252. }
  253. ANKI_ASSERT(m_spatialCount < m_spatials.getSize());
  254. m_spatials[m_spatialCount++] = spatial;
  255. if(m_spatialCount == m_spatials.getSize())
  256. {
  257. flush(hive);
  258. }
  259. });
  260. // Flush the remaining
  261. flush(hive);
  262. // Fire an additional dummy task to decrease the semaphore to zero
  263. GatherVisiblesFromOctreeTask* pself = this; // MSVC workaround
  264. ThreadHiveTask task = ANKI_THREAD_HIVE_TASK({}, pself, nullptr, m_frcCtx->m_visTestsSignalSem);
  265. hive.submitTasks(&task, 1);
  266. }
  267. void GatherVisiblesFromOctreeTask::flush(ThreadHive& hive)
  268. {
  269. if(m_spatialCount)
  270. {
  271. // Create the task
  272. VisibilityTestTask* vis = newInstance<VisibilityTestTask>(SceneGraph::getSingleton().getFrameMemoryPool(), m_frcCtx);
  273. memcpy(&vis->m_spatialsToTest[0], &m_spatials[0], sizeof(m_spatials[0]) * m_spatialCount);
  274. vis->m_spatialToTestCount = m_spatialCount;
  275. // Increase the semaphore to block the CombineResultsTask
  276. m_frcCtx->m_visTestsSignalSem->increaseSemaphore(1);
  277. // Submit task
  278. ThreadHiveTask task = ANKI_THREAD_HIVE_TASK({ self->test(hive, threadId); }, vis, nullptr, m_frcCtx->m_visTestsSignalSem);
  279. hive.submitTasks(&task, 1);
  280. // Clear count
  281. m_spatialCount = 0;
  282. }
  283. }
  284. void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
  285. {
  286. ANKI_TRACE_SCOPED_EVENT(SceneVisTest);
  287. const Frustum& testedFrustum = *m_frcCtx->m_frustum.m_frustum;
  288. ANKI_ASSERT(m_frcCtx->m_primaryFrustum.m_frustum);
  289. const FrustumFlags frustumFlags = m_frcCtx->m_frustum;
  290. const Frustum& primaryFrustum = *m_frcCtx->m_primaryFrustum.m_frustum;
  291. StackMemoryPool& framePool = SceneGraph::getSingleton().getFrameMemoryPool();
  292. WeakArray<RenderQueue> nextQueues;
  293. WeakArray<VisibilityFrustum> nextFrustums;
  294. // Iterate
  295. RenderQueueView& result = m_frcCtx->m_queueViews[taskId];
  296. for(U i = 0; i < m_spatialToTestCount; ++i)
  297. {
  298. Spatial* spatial = m_spatialsToTest[i];
  299. ANKI_ASSERT(spatial);
  300. SceneComponent& comp = spatial->getSceneComponent();
  301. const U8 compClassId = spatial->getSceneComponentClassId();
  302. const Aabb& aabb = spatial->getAabbWorldSpace();
  303. auto isInside = [&] {
  304. return spatial->getAlwaysVisible() || (testedFrustum.insideFrustum(aabb) && testAgainstRasterizer(aabb));
  305. };
  306. if(compClassId == ModelComponent::getStaticClassId())
  307. {
  308. const ModelComponent& modelc = static_cast<ModelComponent&>(comp);
  309. const Bool isShadowFrustum = frustumFlags.m_gatherShadowCasterModelComponents;
  310. if(!modelc.isEnabled() || (isShadowFrustum && !modelc.getCastsShadow()) || !isInside())
  311. {
  312. continue;
  313. }
  314. const Plane& nearPlane = primaryFrustum.getViewPlanes()[FrustumPlaneType::kNear];
  315. const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, aabb));
  316. const U8 lod = computeLod(primaryFrustum, distanceFromCamera);
  317. WeakArray<RenderableQueueElement> elements;
  318. modelc.setupRenderableQueueElements(lod, (isShadowFrustum) ? RenderingTechnique::kDepth : RenderingTechnique::kGBuffer, elements);
  319. for(RenderableQueueElement& el : elements)
  320. {
  321. el.m_distanceFromCamera = distanceFromCamera;
  322. *result.m_renderables.newElement() = el;
  323. }
  324. modelc.setupRenderableQueueElements(lod, RenderingTechnique::kForward, elements);
  325. for(RenderableQueueElement& el : elements)
  326. {
  327. el.m_distanceFromCamera = distanceFromCamera;
  328. *result.m_forwardShadingRenderables.newElement() = el;
  329. }
  330. if(frustumFlags.m_gatherRayTracingModelComponents)
  331. {
  332. WeakArray<RayTracingInstanceQueueElement> rtElements;
  333. modelc.setupRayTracingInstanceQueueElements(lod, RenderingTechnique::kRtShadow, rtElements);
  334. for(RayTracingInstanceQueueElement& el : rtElements)
  335. {
  336. *result.m_rayTracingInstances.newElement() = el;
  337. }
  338. }
  339. // Update timestamp
  340. ANKI_ASSERT(comp.getTimestamp() > 0);
  341. m_frcCtx->m_queueViews[taskId].m_timestamp = max(m_frcCtx->m_queueViews[taskId].m_timestamp, comp.getTimestamp());
  342. }
  343. else if(compClassId == ParticleEmitterComponent::getStaticClassId())
  344. {
  345. const ParticleEmitterComponent& partemitc = static_cast<ParticleEmitterComponent&>(comp);
  346. if(!partemitc.isEnabled() || !isInside())
  347. {
  348. continue;
  349. }
  350. const Plane& nearPlane = primaryFrustum.getViewPlanes()[FrustumPlaneType::kNear];
  351. const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, aabb));
  352. Bool updateTimestamp = false;
  353. WeakArray<RenderableQueueElement> elements;
  354. partemitc.setupRenderableQueueElements(RenderingTechnique::kGBuffer, elements);
  355. for(RenderableQueueElement& el : elements)
  356. {
  357. el.m_distanceFromCamera = distanceFromCamera;
  358. *result.m_renderables.newElement() = el;
  359. updateTimestamp = true;
  360. }
  361. partemitc.setupRenderableQueueElements(RenderingTechnique::kForward, elements);
  362. for(RenderableQueueElement& el : elements)
  363. {
  364. el.m_distanceFromCamera = distanceFromCamera;
  365. *result.m_forwardShadingRenderables.newElement() = el;
  366. }
  367. // Update timestamp
  368. if(updateTimestamp)
  369. {
  370. ANKI_ASSERT(comp.getTimestamp() > 0);
  371. m_frcCtx->m_queueViews[taskId].m_timestamp = max(m_frcCtx->m_queueViews[taskId].m_timestamp, comp.getTimestamp());
  372. }
  373. }
  374. else if(compClassId == LightComponent::getStaticClassId())
  375. {
  376. const LightComponent& lightc = static_cast<LightComponent&>(comp);
  377. if(lightc.getLightComponentType() != LightComponentType::kDirectional && !isInside())
  378. {
  379. continue;
  380. }
  381. // Check if it casts shadow
  382. Bool castsShadow = lightc.getShadowEnabled();
  383. if(castsShadow && lightc.getLightComponentType() != LightComponentType::kDirectional)
  384. {
  385. // Extra check
  386. // Compute distance from the frustum
  387. const Plane& nearPlane = primaryFrustum.getViewPlanes()[FrustumPlaneType::kNear];
  388. const F32 distFromFrustum = max(0.0f, testPlane(nearPlane, aabb));
  389. const F32 shadowEffectiveDistance = (primaryFrustum.getShadowCascadeCount() > 0)
  390. ? primaryFrustum.getShadowCascadeDistance(primaryFrustum.getShadowCascadeCount() - 1)
  391. : primaryFrustum.getFar();
  392. castsShadow = distFromFrustum < shadowEffectiveDistance;
  393. }
  394. switch(lightc.getLightComponentType())
  395. {
  396. case LightComponentType::kPoint:
  397. {
  398. PointLightQueueElement* el = result.m_pointLights.newElement();
  399. lightc.setupPointLightQueueElement(*el);
  400. if(castsShadow && frustumFlags.m_nonDirectionalLightsCastShadow)
  401. {
  402. nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(framePool, 6), 6);
  403. nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(framePool, 6), 6);
  404. for(U32 f = 0; f < 6; ++f)
  405. {
  406. el->m_shadowRenderQueues[f] = &nextQueues[f];
  407. nextFrustums[f].m_frustum = &lightc.getFrustums()[f];
  408. static_cast<FrustumFlags&>(nextFrustums[f]) = getLightFrustumFlags();
  409. }
  410. }
  411. else
  412. {
  413. zeroMemory(el->m_shadowRenderQueues);
  414. }
  415. break;
  416. }
  417. case LightComponentType::kSpot:
  418. {
  419. SpotLightQueueElement* el = result.m_spotLights.newElement();
  420. lightc.setupSpotLightQueueElement(*el);
  421. if(castsShadow && frustumFlags.m_nonDirectionalLightsCastShadow)
  422. {
  423. nextQueues = WeakArray<RenderQueue>(newInstance<RenderQueue>(framePool), 1);
  424. el->m_shadowRenderQueue = &nextQueues[0];
  425. nextFrustums = WeakArray<VisibilityFrustum>(newInstance<VisibilityFrustum>(framePool), 1);
  426. nextFrustums[0].m_frustum = &lightc.getFrustums()[0];
  427. static_cast<FrustumFlags&>(nextFrustums[0]) = getLightFrustumFlags();
  428. }
  429. else
  430. {
  431. el->m_shadowRenderQueue = nullptr;
  432. }
  433. break;
  434. }
  435. case LightComponentType::kDirectional:
  436. {
  437. U32 cascadeCount;
  438. if(!castsShadow || !frustumFlags.m_directionalLightsCastShadow)
  439. {
  440. cascadeCount = 0;
  441. }
  442. else
  443. {
  444. cascadeCount = testedFrustum.getShadowCascadeCount();
  445. }
  446. ANKI_ASSERT(cascadeCount <= kMaxShadowCascades);
  447. // Create some dummy frustum components and initialize them
  448. WeakArray<Frustum> frustums;
  449. if(cascadeCount)
  450. {
  451. nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(framePool, cascadeCount), cascadeCount);
  452. nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(framePool, cascadeCount), cascadeCount);
  453. frustums = WeakArray<Frustum>(newArray<Frustum>(framePool, cascadeCount), cascadeCount);
  454. }
  455. for(U32 i = 0; i < cascadeCount; ++i)
  456. {
  457. nextFrustums[i].m_frustum = &frustums[i];
  458. static_cast<FrustumFlags&>(nextFrustums[i]) = getDirectionalLightFrustumFlags();
  459. result.m_directionalLight.m_shadowRenderQueues[i] = &nextQueues[i];
  460. }
  461. lightc.setupDirectionalLightQueueElement(testedFrustum, result.m_directionalLight, frustums);
  462. // Despite the fact that it's the same light it will have different properties if viewed by different
  463. // cameras. If the renderer finds the same UUID it will think it's cached and use wrong shadow tiles.
  464. // That's why we need to change its UUID and bind it to the frustum that is currently viewing the light
  465. result.m_directionalLight.m_uuid = ptrToNumber(&testedFrustum);
  466. break;
  467. }
  468. default:
  469. ANKI_ASSERT(0);
  470. }
  471. }
  472. else if(compClassId == LensFlareComponent::getStaticClassId())
  473. {
  474. const LensFlareComponent& flarec = static_cast<LensFlareComponent&>(comp);
  475. if(!isInside() || !flarec.isEnabled())
  476. {
  477. continue;
  478. }
  479. LensFlareQueueElement* el = result.m_lensFlares.newElement();
  480. flarec.setupLensFlareQueueElement(*el);
  481. }
  482. else if(compClassId == ReflectionProbeComponent::getStaticClassId())
  483. {
  484. if(!isInside())
  485. {
  486. continue;
  487. }
  488. ReflectionProbeComponent& reflc = static_cast<ReflectionProbeComponent&>(comp);
  489. if(reflc.getReflectionNeedsRefresh() && m_frcCtx->m_reflectionProbesForRefreshCount.fetchAdd(1) == 0)
  490. {
  491. ReflectionProbeQueueElementForRefresh* el = newInstance<ReflectionProbeQueueElementForRefresh>(framePool);
  492. m_frcCtx->m_reflectionProbeForRefresh = el;
  493. reflc.setupReflectionProbeQueueElementForRefresh(*el);
  494. reflc.setReflectionNeedsRefresh(false);
  495. nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(framePool, 6), 6);
  496. nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(framePool, 6), 6);
  497. for(U32 i = 0; i < 6; ++i)
  498. {
  499. el->m_renderQueues[i] = &nextQueues[i];
  500. nextFrustums[i].m_frustum = &reflc.getFrustums()[i];
  501. static_cast<FrustumFlags&>(nextFrustums[i]) = getProbeFrustumFlags();
  502. }
  503. }
  504. else if(!reflc.getReflectionNeedsRefresh())
  505. {
  506. ReflectionProbeQueueElement* el = result.m_reflectionProbes.newElement();
  507. reflc.setupReflectionProbeQueueElement(*el);
  508. }
  509. }
  510. else if(compClassId == DecalComponent::getStaticClassId())
  511. {
  512. const DecalComponent& decalc = static_cast<DecalComponent&>(comp);
  513. if(!isInside() || !decalc.isEnabled())
  514. {
  515. continue;
  516. }
  517. DecalQueueElement* el = result.m_decals.newElement();
  518. decalc.setupDecalQueueElement(*el);
  519. }
  520. else if(compClassId == FogDensityComponent::getStaticClassId())
  521. {
  522. if(!isInside())
  523. {
  524. continue;
  525. }
  526. const FogDensityComponent& fogc = static_cast<FogDensityComponent&>(comp);
  527. FogDensityQueueElement* el = result.m_fogDensityVolumes.newElement();
  528. fogc.setupFogDensityQueueElement(*el);
  529. }
  530. else if(compClassId == GlobalIlluminationProbeComponent::getStaticClassId())
  531. {
  532. if(!isInside())
  533. {
  534. continue;
  535. }
  536. GlobalIlluminationProbeComponent& giprobec = static_cast<GlobalIlluminationProbeComponent&>(comp);
  537. if(giprobec.needsRefresh() && m_frcCtx->m_giProbesForRefreshCount.fetchAdd(1) == 0)
  538. {
  539. nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(framePool, 6), 6);
  540. nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(framePool, 6), 6);
  541. GlobalIlluminationProbeQueueElementForRefresh* el = newInstance<GlobalIlluminationProbeQueueElementForRefresh>(framePool);
  542. m_frcCtx->m_giProbeForRefresh = el;
  543. giprobec.setupGlobalIlluminationProbeQueueElementForRefresh(*el);
  544. giprobec.progressRefresh();
  545. for(U32 i = 0; i < 6; ++i)
  546. {
  547. el->m_renderQueues[i] = &nextQueues[i];
  548. nextFrustums[i].m_frustum = &giprobec.getFrustums()[i];
  549. static_cast<FrustumFlags&>(nextFrustums[i]) = getProbeFrustumFlags();
  550. }
  551. }
  552. GlobalIlluminationProbeQueueElement* el = result.m_giProbes.newElement();
  553. giprobec.setupGlobalIlluminationProbeQueueElement(*el);
  554. }
  555. else if(compClassId == UiComponent::getStaticClassId())
  556. {
  557. if(!isInside())
  558. {
  559. continue;
  560. }
  561. const UiComponent& uic = static_cast<UiComponent&>(comp);
  562. UiQueueElement* el = result.m_uis.newElement();
  563. uic.setupUiQueueElement(*el);
  564. }
  565. else if(compClassId == SkyboxComponent::getStaticClassId())
  566. {
  567. if(!isInside())
  568. {
  569. continue;
  570. }
  571. const SkyboxComponent& skyboxc = static_cast<SkyboxComponent&>(comp);
  572. skyboxc.setupSkyboxQueueElement(result.m_skybox);
  573. result.m_skyboxSet = true;
  574. }
  575. else
  576. {
  577. ANKI_ASSERT(0);
  578. }
  579. // Add more frustums to the list
  580. if(nextQueues.getSize() > 0)
  581. {
  582. ANKI_ASSERT(nextFrustums.getSize() == nextQueues.getSize());
  583. for(U32 i = 0; i < nextQueues.getSize(); ++i)
  584. {
  585. m_frcCtx->m_visCtx->submitNewWork(nextFrustums[i], m_frcCtx->m_primaryFrustum, nextQueues[i], hive);
  586. }
  587. }
  588. } // end for
  589. }
  590. void CombineResultsTask::combine()
  591. {
  592. ANKI_TRACE_SCOPED_EVENT(SceneVisCombine);
  593. RenderQueue& results = *m_frcCtx->m_renderQueue;
  594. // Compute the timestamp
  595. const U32 threadCount = m_frcCtx->m_queueViews.getSize();
  596. results.m_shadowRenderablesLastUpdateTimestamp = 0;
  597. U32 renderableCount = 0;
  598. for(U32 i = 0; i < threadCount; ++i)
  599. {
  600. results.m_shadowRenderablesLastUpdateTimestamp = max(results.m_shadowRenderablesLastUpdateTimestamp, m_frcCtx->m_queueViews[i].m_timestamp);
  601. renderableCount += m_frcCtx->m_queueViews[i].m_renderables.m_elementCount;
  602. }
  603. if(renderableCount)
  604. {
  605. ANKI_ASSERT(results.m_shadowRenderablesLastUpdateTimestamp > 0);
  606. }
  607. else
  608. {
  609. ANKI_ASSERT(results.m_shadowRenderablesLastUpdateTimestamp == 0);
  610. }
  611. if(m_frcCtx->m_frustum.m_frustum->getUpdatedThisFrame())
  612. {
  613. results.m_shadowRenderablesLastUpdateTimestamp = GlobalFrameIndex::getSingleton().m_value;
  614. }
  615. #define ANKI_VIS_COMBINE(t_, member_) \
  616. { \
  617. Array<TRenderQueueElementStorage<t_>, 64> subStorages; \
  618. for(U32 i = 0; i < threadCount; ++i) \
  619. { \
  620. subStorages[i] = m_frcCtx->m_queueViews[i].member_; \
  621. } \
  622. combineQueueElements<t_>(WeakArray<TRenderQueueElementStorage<t_>>(&subStorages[0], threadCount), nullptr, results.member_, nullptr); \
  623. }
  624. ANKI_VIS_COMBINE(RenderableQueueElement, m_renderables);
  625. ANKI_VIS_COMBINE(RenderableQueueElement, m_forwardShadingRenderables);
  626. ANKI_VIS_COMBINE(PointLightQueueElement, m_pointLights);
  627. ANKI_VIS_COMBINE(SpotLightQueueElement, m_spotLights);
  628. ANKI_VIS_COMBINE(ReflectionProbeQueueElement, m_reflectionProbes);
  629. ANKI_VIS_COMBINE(LensFlareQueueElement, m_lensFlares);
  630. ANKI_VIS_COMBINE(DecalQueueElement, m_decals);
  631. ANKI_VIS_COMBINE(FogDensityQueueElement, m_fogDensityVolumes);
  632. ANKI_VIS_COMBINE(GlobalIlluminationProbeQueueElement, m_giProbes);
  633. ANKI_VIS_COMBINE(GenericGpuComputeJobQueueElement, m_genericGpuComputeJobs);
  634. ANKI_VIS_COMBINE(RayTracingInstanceQueueElement, m_rayTracingInstances);
  635. ANKI_VIS_COMBINE(UiQueueElement, m_uis);
  636. #undef ANKI_VIS_COMBINE
  637. results.m_reflectionProbeForRefresh = m_frcCtx->m_reflectionProbeForRefresh;
  638. results.m_giProbeForRefresh = m_frcCtx->m_giProbeForRefresh;
  639. for(U32 i = 0; i < threadCount; ++i)
  640. {
  641. if(m_frcCtx->m_queueViews[i].m_directionalLight.m_uuid != 0)
  642. {
  643. results.m_directionalLight = m_frcCtx->m_queueViews[i].m_directionalLight;
  644. }
  645. if(m_frcCtx->m_queueViews[i].m_skyboxSet)
  646. {
  647. results.m_skybox = m_frcCtx->m_queueViews[i].m_skybox;
  648. }
  649. }
  650. const Bool isShadowFrustum = m_frcCtx->m_frustum.m_gatherShadowCasterModelComponents;
  651. // Sort some of the arrays
  652. if(!isShadowFrustum)
  653. {
  654. std::sort(results.m_renderables.getBegin(), results.m_renderables.getEnd(), MaterialDistanceSortFunctor());
  655. std::sort(results.m_forwardShadingRenderables.getBegin(), results.m_forwardShadingRenderables.getEnd(),
  656. RevDistanceSortFunctor<RenderableQueueElement>());
  657. }
  658. std::sort(results.m_giProbes.getBegin(), results.m_giProbes.getEnd());
  659. // Sort the ligths as well because some rendering effects expect the same order from frame to frame
  660. std::sort(results.m_pointLights.getBegin(), results.m_pointLights.getEnd(),
  661. [](const PointLightQueueElement& a, const PointLightQueueElement& b) -> Bool {
  662. if(a.hasShadow() != b.hasShadow())
  663. {
  664. return a.hasShadow() < b.hasShadow();
  665. }
  666. else
  667. {
  668. return a.m_uuid < b.m_uuid;
  669. }
  670. });
  671. std::sort(results.m_spotLights.getBegin(), results.m_spotLights.getEnd(),
  672. [](const SpotLightQueueElement& a, const SpotLightQueueElement& b) -> Bool {
  673. if(a.hasShadow() != b.hasShadow())
  674. {
  675. return a.hasShadow() > b.hasShadow();
  676. }
  677. else
  678. {
  679. return a.m_uuid < b.m_uuid;
  680. }
  681. });
  682. const GpuSceneContiguousArrays& arrays = GpuSceneContiguousArrays::getSingleton();
  683. auto setOffset = [&](ClusteredObjectType type, GpuSceneContiguousArrayType type2) {
  684. results.m_clustererObjectsArrayOffsets[type] = arrays.getElementCount(type2) ? arrays.getArrayBaseOffset(type2) : 0;
  685. results.m_clustererObjectsArrayRanges[type] = arrays.getElementCount(type2) * arrays.getElementSize(type2);
  686. };
  687. setOffset(ClusteredObjectType::kPointLight, GpuSceneContiguousArrayType::kPointLights);
  688. setOffset(ClusteredObjectType::kSpotLight, GpuSceneContiguousArrayType::kSpotLights);
  689. setOffset(ClusteredObjectType::kDecal, GpuSceneContiguousArrayType::kDecals);
  690. setOffset(ClusteredObjectType::kFogDensityVolume, GpuSceneContiguousArrayType::kFogDensityVolumes);
  691. setOffset(ClusteredObjectType::kGlobalIlluminationProbe, GpuSceneContiguousArrayType::kGlobalIlluminationProbes);
  692. setOffset(ClusteredObjectType::kReflectionProbe, GpuSceneContiguousArrayType::kReflectionProbes);
  693. // Cleanup
  694. if(m_frcCtx->m_r)
  695. {
  696. m_frcCtx->m_r->~SoftwareRasterizer();
  697. }
  698. }
  699. template<typename T>
  700. void CombineResultsTask::combineQueueElements(WeakArray<TRenderQueueElementStorage<T>> subStorages,
  701. WeakArray<TRenderQueueElementStorage<U32>>* ptrSubStorages, WeakArray<T>& combined,
  702. WeakArray<T*>* ptrCombined)
  703. {
  704. StackMemoryPool& framePool = SceneGraph::getSingleton().getFrameMemoryPool();
  705. U32 totalElCount = subStorages[0].m_elementCount;
  706. U32 biggestSubStorageIdx = 0;
  707. for(U32 i = 1; i < subStorages.getSize(); ++i)
  708. {
  709. totalElCount += subStorages[i].m_elementCount;
  710. if(subStorages[i].m_elementStorage > subStorages[biggestSubStorageIdx].m_elementStorage)
  711. {
  712. biggestSubStorageIdx = i;
  713. }
  714. }
  715. if(totalElCount == 0)
  716. {
  717. return;
  718. }
  719. // Count ptrSubStorage elements
  720. T** ptrIt = nullptr;
  721. if(ptrSubStorages != nullptr)
  722. {
  723. ANKI_ASSERT(ptrCombined);
  724. U32 ptrTotalElCount = (*ptrSubStorages)[0].m_elementCount;
  725. for(U32 i = 1; i < ptrSubStorages->getSize(); ++i)
  726. {
  727. ptrTotalElCount += (*ptrSubStorages)[i].m_elementCount;
  728. }
  729. // Create the new storage
  730. if(ptrTotalElCount > 0)
  731. {
  732. ptrIt = newArray<T*>(framePool, ptrTotalElCount);
  733. *ptrCombined = WeakArray<T*>(ptrIt, ptrTotalElCount);
  734. }
  735. }
  736. T* it;
  737. if(totalElCount > subStorages[biggestSubStorageIdx].m_elementStorage)
  738. {
  739. // Can't reuse any of the existing storage, will allocate a brand new one
  740. it = newArray<T>(framePool, totalElCount);
  741. biggestSubStorageIdx = kMaxU32;
  742. combined = WeakArray<T>(it, totalElCount);
  743. }
  744. else
  745. {
  746. // Will reuse existing storage
  747. it = subStorages[biggestSubStorageIdx].m_elements + subStorages[biggestSubStorageIdx].m_elementCount;
  748. combined = WeakArray<T>(subStorages[biggestSubStorageIdx].m_elements, totalElCount);
  749. }
  750. for(U32 i = 0; i < subStorages.getSize(); ++i)
  751. {
  752. if(subStorages[i].m_elementCount == 0)
  753. {
  754. continue;
  755. }
  756. // Copy the pointers
  757. if(ptrIt)
  758. {
  759. T* base = (i != biggestSubStorageIdx) ? it : subStorages[biggestSubStorageIdx].m_elements;
  760. for(U32 x = 0; x < (*ptrSubStorages)[i].m_elementCount; ++x)
  761. {
  762. ANKI_ASSERT((*ptrSubStorages)[i].m_elements[x] < subStorages[i].m_elementCount);
  763. *ptrIt = base + (*ptrSubStorages)[i].m_elements[x];
  764. ++ptrIt;
  765. }
  766. ANKI_ASSERT(ptrIt <= ptrCombined->getEnd());
  767. }
  768. // Copy the elements
  769. if(i != biggestSubStorageIdx)
  770. {
  771. memcpy(it, subStorages[i].m_elements, sizeof(T) * subStorages[i].m_elementCount);
  772. it += subStorages[i].m_elementCount;
  773. }
  774. }
  775. }
  776. void SceneGraph::doVisibilityTests(SceneNode& camera, SceneGraph& scene, RenderQueue& rqueue)
  777. {
  778. ANKI_TRACE_SCOPED_EVENT(SceneVisTests);
  779. ThreadHive& hive = CoreThreadHive::getSingleton();
  780. VisibilityContext ctx;
  781. CameraComponent& camerac = camera.getFirstComponentOfType<CameraComponent>();
  782. VisibilityFrustum visFrustum;
  783. visFrustum.m_frustum = &camerac.getFrustum();
  784. static_cast<FrustumFlags&>(visFrustum) = getCameraFrustumFlags();
  785. ctx.submitNewWork(visFrustum, visFrustum, rqueue, hive);
  786. if(camerac.getHasExtendedFrustum())
  787. {
  788. VisibilityFrustum evisFrustum;
  789. evisFrustum.m_frustum = &camerac.getExtendedFrustum();
  790. static_cast<FrustumFlags&>(evisFrustum) = getCameraExtendedFrustumFlags();
  791. rqueue.m_rayTracingQueue = newInstance<RenderQueue>(scene.getFrameMemoryPool());
  792. ctx.submitNewWork(evisFrustum, visFrustum, *rqueue.m_rayTracingQueue, hive);
  793. }
  794. hive.waitAllTasks();
  795. }
  796. } // end namespace anki