Visibility.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. // Copyright (C) 2009-2021, 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/FrustumComponent.h>
  8. #include <AnKi/Scene/Components/LensFlareComponent.h>
  9. #include <AnKi/Scene/Components/RenderComponent.h>
  10. #include <AnKi/Scene/Components/ReflectionProbeComponent.h>
  11. #include <AnKi/Scene/Components/DecalComponent.h>
  12. #include <AnKi/Scene/Components/MoveComponent.h>
  13. #include <AnKi/Scene/Components/FogDensityComponent.h>
  14. #include <AnKi/Scene/Components/LightComponent.h>
  15. #include <AnKi/Scene/Components/SpatialComponent.h>
  16. #include <AnKi/Scene/Components/GlobalIlluminationProbeComponent.h>
  17. #include <AnKi/Scene/Components/GenericGpuComputeJobComponent.h>
  18. #include <AnKi/Scene/Components/UiComponent.h>
  19. #include <AnKi/Renderer/MainRenderer.h>
  20. #include <AnKi/Util/Logger.h>
  21. #include <AnKi/Util/ThreadHive.h>
  22. namespace anki {
  23. static U8 computeLod(const FrustumComponent& frc, F32 distanceFromTheNearPlane)
  24. {
  25. static_assert(MAX_LOD_COUNT == 3, "Wrong assumption");
  26. U8 lod;
  27. if(distanceFromTheNearPlane < 0.0f)
  28. {
  29. // In RT objects may fall behind the camera, use the max LOD on those
  30. lod = 2;
  31. }
  32. else if(distanceFromTheNearPlane <= frc.getLodDistance(0))
  33. {
  34. lod = 0;
  35. }
  36. else if(distanceFromTheNearPlane <= frc.getLodDistance(1))
  37. {
  38. lod = 1;
  39. }
  40. else
  41. {
  42. lod = 2;
  43. }
  44. return lod;
  45. }
  46. static Bool spatialInsideFrustum(const FrustumComponent& frc, const SpatialComponent& spc)
  47. {
  48. switch(spc.getCollisionShapeType())
  49. {
  50. case CollisionShapeType::OBB:
  51. return frc.insideFrustum(spc.getCollisionShape<Obb>());
  52. break;
  53. case CollisionShapeType::AABB:
  54. return frc.insideFrustum(spc.getCollisionShape<Aabb>());
  55. break;
  56. case CollisionShapeType::SPHERE:
  57. return frc.insideFrustum(spc.getCollisionShape<Sphere>());
  58. break;
  59. case CollisionShapeType::CONVEX_HULL:
  60. return frc.insideFrustum(spc.getCollisionShape<ConvexHullShape>());
  61. break;
  62. default:
  63. ANKI_ASSERT(0);
  64. return false;
  65. }
  66. }
  67. void VisibilityContext::submitNewWork(const FrustumComponent& frc, const FrustumComponent& primaryFrustum,
  68. RenderQueue& rqueue, ThreadHive& hive)
  69. {
  70. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_SUBMIT_WORK);
  71. // Check enabled and make sure that the results are null (this can happen on multiple on circular viewing)
  72. if(ANKI_UNLIKELY(frc.getEnabledVisibilityTests() == FrustumComponentVisibilityTestFlag::NONE))
  73. {
  74. return;
  75. }
  76. rqueue.m_cameraTransform = Mat4(frc.getWorldTransform());
  77. rqueue.m_viewMatrix = frc.getViewMatrix();
  78. rqueue.m_projectionMatrix = frc.getProjectionMatrix();
  79. rqueue.m_viewProjectionMatrix = frc.getViewProjectionMatrix();
  80. rqueue.m_previousViewProjectionMatrix = frc.getPreviousViewProjectionMatrix();
  81. rqueue.m_cameraNear = frc.getNear();
  82. rqueue.m_cameraFar = frc.getFar();
  83. if(frc.getFrustumType() == FrustumType::PERSPECTIVE)
  84. {
  85. rqueue.m_cameraFovX = frc.getFovX();
  86. rqueue.m_cameraFovY = frc.getFovY();
  87. }
  88. else
  89. {
  90. rqueue.m_cameraFovX = rqueue.m_cameraFovY = 0.0f;
  91. }
  92. rqueue.m_effectiveShadowDistance = frc.getEffectiveShadowDistance();
  93. auto alloc = m_scene->getFrameAllocator();
  94. // Check if this frc was tested before
  95. {
  96. LockGuard<Mutex> l(m_mtx);
  97. // Check if already in the list
  98. for(const FrustumComponent* x : m_testedFrcs)
  99. {
  100. if(x == &frc)
  101. {
  102. return;
  103. }
  104. }
  105. // Not there, push it
  106. m_testedFrcs.pushBack(alloc, &frc);
  107. }
  108. // Prepare the ctx
  109. FrustumVisibilityContext* frcCtx = alloc.newInstance<FrustumVisibilityContext>();
  110. frcCtx->m_visCtx = this;
  111. frcCtx->m_frc = &frc;
  112. frcCtx->m_primaryFrustum = &primaryFrustum;
  113. frcCtx->m_queueViews.create(alloc, hive.getThreadCount());
  114. frcCtx->m_visTestsSignalSem = hive.newSemaphore(1);
  115. frcCtx->m_renderQueue = &rqueue;
  116. // Submit new work
  117. //
  118. // Software rasterizer task
  119. ThreadHiveSemaphore* prepareRasterizerSem = nullptr;
  120. if(!!(frc.getEnabledVisibilityTests() & FrustumComponentVisibilityTestFlag::OCCLUDERS) && frc.hasCoverageBuffer())
  121. {
  122. // Gather triangles task
  123. ThreadHiveTask fillDepthTask =
  124. ANKI_THREAD_HIVE_TASK({ self->fill(); }, alloc.newInstance<FillRasterizerWithCoverageTask>(frcCtx), nullptr,
  125. hive.newSemaphore(1));
  126. hive.submitTasks(&fillDepthTask, 1);
  127. prepareRasterizerSem = fillDepthTask.m_signalSemaphore;
  128. }
  129. if(!!(frc.getEnabledVisibilityTests() & FrustumComponentVisibilityTestFlag::OCCLUDERS))
  130. {
  131. rqueue.m_fillCoverageBufferCallback = FrustumComponent::fillCoverageBufferCallback;
  132. rqueue.m_fillCoverageBufferCallbackUserData = static_cast<void*>(const_cast<FrustumComponent*>(&frc));
  133. }
  134. // Gather visibles from the octree. No need to signal anything because it will spawn new tasks
  135. ThreadHiveTask gatherTask =
  136. ANKI_THREAD_HIVE_TASK({ self->gather(hive); }, alloc.newInstance<GatherVisiblesFromOctreeTask>(frcCtx),
  137. prepareRasterizerSem, nullptr);
  138. hive.submitTasks(&gatherTask, 1);
  139. // Combind results task
  140. ANKI_ASSERT(frcCtx->m_visTestsSignalSem);
  141. ThreadHiveTask combineTask = ANKI_THREAD_HIVE_TASK(
  142. { self->combine(); }, alloc.newInstance<CombineResultsTask>(frcCtx), frcCtx->m_visTestsSignalSem, nullptr);
  143. hive.submitTasks(&combineTask, 1);
  144. }
  145. void FillRasterizerWithCoverageTask::fill()
  146. {
  147. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_FILL_DEPTH);
  148. auto alloc = m_frcCtx->m_visCtx->m_scene->getFrameAllocator();
  149. // Get the C-Buffer
  150. ConstWeakArray<F32> depthBuff;
  151. U32 width;
  152. U32 height;
  153. m_frcCtx->m_frc->getCoverageBufferInfo(depthBuff, width, height);
  154. ANKI_ASSERT(width > 0 && height > 0 && depthBuff.getSize() > 0);
  155. // Init the rasterizer
  156. m_frcCtx->m_r = alloc.newInstance<SoftwareRasterizer>();
  157. m_frcCtx->m_r->init(alloc);
  158. m_frcCtx->m_r->prepare(m_frcCtx->m_frc->getViewMatrix(), m_frcCtx->m_frc->getProjectionMatrix(), width, height);
  159. // Do the work
  160. m_frcCtx->m_r->fillDepthBuffer(depthBuff);
  161. }
  162. void GatherVisiblesFromOctreeTask::gather(ThreadHive& hive)
  163. {
  164. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_OCTREE);
  165. U32 testIdx = m_frcCtx->m_visCtx->m_testsCount.fetchAdd(1);
  166. // Walk the tree
  167. m_frcCtx->m_visCtx->m_scene->getOctree().walkTree(
  168. testIdx,
  169. [&](const Aabb& box) {
  170. Bool visible = m_frcCtx->m_frc->insideFrustum(box);
  171. if(visible && m_frcCtx->m_r)
  172. {
  173. visible = m_frcCtx->m_r->visibilityTest(box);
  174. }
  175. return visible;
  176. },
  177. [&](void* placeableUserData) {
  178. ANKI_ASSERT(placeableUserData);
  179. SpatialComponent* scomp = static_cast<SpatialComponent*>(placeableUserData);
  180. ANKI_ASSERT(m_spatialCount < m_spatials.getSize());
  181. m_spatials[m_spatialCount++] = scomp;
  182. if(m_spatialCount == m_spatials.getSize())
  183. {
  184. flush(hive);
  185. }
  186. });
  187. // Flush the remaining
  188. flush(hive);
  189. // Fire an additional dummy task to decrease the semaphore to zero
  190. GatherVisiblesFromOctreeTask* pself = this; // MSVC workaround
  191. ThreadHiveTask task = ANKI_THREAD_HIVE_TASK({}, pself, nullptr, m_frcCtx->m_visTestsSignalSem);
  192. hive.submitTasks(&task, 1);
  193. }
  194. void GatherVisiblesFromOctreeTask::flush(ThreadHive& hive)
  195. {
  196. if(m_spatialCount)
  197. {
  198. // Create the task
  199. VisibilityTestTask* vis =
  200. m_frcCtx->m_visCtx->m_scene->getFrameAllocator().newInstance<VisibilityTestTask>(m_frcCtx);
  201. memcpy(&vis->m_spatialsToTest[0], &m_spatials[0], sizeof(m_spatials[0]) * m_spatialCount);
  202. vis->m_spatialToTestCount = m_spatialCount;
  203. // Increase the semaphore to block the CombineResultsTask
  204. m_frcCtx->m_visTestsSignalSem->increaseSemaphore(1);
  205. // Submit task
  206. ThreadHiveTask task =
  207. ANKI_THREAD_HIVE_TASK({ self->test(hive, threadId); }, vis, nullptr, m_frcCtx->m_visTestsSignalSem);
  208. hive.submitTasks(&task, 1);
  209. // Clear count
  210. m_spatialCount = 0;
  211. }
  212. }
  213. void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
  214. {
  215. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_TEST);
  216. const FrustumComponent& testedFrc = *m_frcCtx->m_frc;
  217. const FrustumComponentVisibilityTestFlag enabledVisibilityTests = testedFrc.getEnabledVisibilityTests();
  218. ANKI_ASSERT(enabledVisibilityTests != FrustumComponentVisibilityTestFlag::NONE);
  219. ANKI_ASSERT(m_frcCtx->m_primaryFrustum);
  220. const FrustumComponent& primaryFrc = *m_frcCtx->m_primaryFrustum;
  221. const SceneNode& testedNode = testedFrc.getSceneNode();
  222. auto alloc = m_frcCtx->m_visCtx->m_scene->getFrameAllocator();
  223. Timestamp& timestamp = m_frcCtx->m_queueViews[taskId].m_timestamp;
  224. timestamp = testedNode.getComponentMaxTimestamp();
  225. const Bool wantsEarlyZ = !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::EARLY_Z)
  226. && m_frcCtx->m_visCtx->m_earlyZDist > 0.0f;
  227. // Iterate
  228. RenderQueueView& result = m_frcCtx->m_queueViews[taskId];
  229. for(U i = 0; i < m_spatialToTestCount; ++i)
  230. {
  231. SpatialComponent* spatialC = m_spatialsToTest[i];
  232. ANKI_ASSERT(spatialC);
  233. SceneNode& node = spatialC->getSceneNode();
  234. // Skip if it is the same
  235. if(ANKI_UNLIKELY(&testedNode == &node))
  236. {
  237. continue;
  238. }
  239. // Check what components the frustum needs
  240. Bool wantNode = false;
  241. const RenderComponent* rc = nullptr;
  242. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS)
  243. && (rc = node.tryGetFirstComponentOfType<RenderComponent>());
  244. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::SHADOW_CASTERS)
  245. && (rc = node.tryGetFirstComponentOfType<RenderComponent>())
  246. && !!(rc->getFlags() & RenderComponentFlag::CASTS_SHADOW);
  247. const RenderComponent* rtRc = nullptr;
  248. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::ALL_RAY_TRACING)
  249. && (rtRc = node.tryGetFirstComponentOfType<RenderComponent>()) && rtRc->getSupportsRayTracing();
  250. const LightComponent* lc = nullptr;
  251. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::LIGHT_COMPONENTS)
  252. && (lc = node.tryGetFirstComponentOfType<LightComponent>());
  253. const LensFlareComponent* lfc = nullptr;
  254. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::LENS_FLARE_COMPONENTS)
  255. && (lfc = node.tryGetFirstComponentOfType<LensFlareComponent>());
  256. const ReflectionProbeComponent* reflc = nullptr;
  257. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::REFLECTION_PROBES)
  258. && (reflc = node.tryGetFirstComponentOfType<ReflectionProbeComponent>());
  259. DecalComponent* decalc = nullptr;
  260. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::DECALS)
  261. && (decalc = node.tryGetFirstComponentOfType<DecalComponent>());
  262. const FogDensityComponent* fogc = nullptr;
  263. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS)
  264. && (fogc = node.tryGetFirstComponentOfType<FogDensityComponent>());
  265. GlobalIlluminationProbeComponent* giprobec = nullptr;
  266. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::GLOBAL_ILLUMINATION_PROBES)
  267. && (giprobec = node.tryGetFirstComponentOfType<GlobalIlluminationProbeComponent>());
  268. GenericGpuComputeJobComponent* computec = nullptr;
  269. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::GENERIC_COMPUTE_JOB_COMPONENTS)
  270. && (computec = node.tryGetFirstComponentOfType<GenericGpuComputeJobComponent>());
  271. UiComponent* uic = nullptr;
  272. wantNode |= !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::UI_COMPONENTS)
  273. && (uic = node.tryGetFirstComponentOfType<UiComponent>());
  274. if(ANKI_UNLIKELY(!wantNode))
  275. {
  276. // Skip node
  277. continue;
  278. }
  279. const SpatialComponent* spatialc = node.tryGetFirstComponentOfType<SpatialComponent>();
  280. if(ANKI_UNLIKELY(spatialc == nullptr))
  281. {
  282. continue;
  283. }
  284. if(!spatialc->getAlwaysVisible()
  285. && (!spatialInsideFrustum(testedFrc, *spatialc) || !testAgainstRasterizer(spatialc->getAabbWorldSpace())))
  286. {
  287. continue;
  288. }
  289. WeakArray<RenderQueue> nextQueues;
  290. WeakArray<FrustumComponent> nextQueueFrustumComponents; // Optional
  291. node.iterateComponentsOfType<RenderComponent>([&](const RenderComponent& rc) {
  292. RenderableQueueElement* el;
  293. if(!!(rc.getFlags() & RenderComponentFlag::FORWARD_SHADING))
  294. {
  295. el = result.m_forwardShadingRenderables.newElement(alloc);
  296. }
  297. else
  298. {
  299. el = result.m_renderables.newElement(alloc);
  300. }
  301. rc.setupRenderableQueueElement(*el);
  302. // Compute distance from the frustum
  303. const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::NEAR];
  304. el->m_distanceFromCamera = !!(rc.getFlags() & RenderComponentFlag::SORT_LAST)
  305. ? primaryFrc.getFar()
  306. : max(0.0f, testPlane(nearPlane, spatialc->getAabbWorldSpace()));
  307. el->m_lod = computeLod(primaryFrc, el->m_distanceFromCamera);
  308. // Add to early Z
  309. if(wantsEarlyZ && el->m_distanceFromCamera < m_frcCtx->m_visCtx->m_earlyZDist
  310. && !(rc.getFlags() & RenderComponentFlag::FORWARD_SHADING))
  311. {
  312. RenderableQueueElement* el2 = result.m_earlyZRenderables.newElement(alloc);
  313. *el2 = *el;
  314. }
  315. // Add to RT
  316. if(rtRc)
  317. {
  318. RayTracingInstanceQueueElement* el = result.m_rayTracingInstances.newElement(alloc);
  319. // Compute the LOD
  320. const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::NEAR];
  321. const F32 dist = testPlane(nearPlane, spatialc->getAabbWorldSpace());
  322. rc.setupRayTracingInstanceQueueElement(computeLod(primaryFrc, dist), *el);
  323. }
  324. });
  325. if(lc)
  326. {
  327. // Check if it casts shadow
  328. Bool castsShadow = lc->getShadowEnabled();
  329. if(castsShadow && lc->getLightComponentType() != LightComponentType::DIRECTIONAL)
  330. {
  331. // Extra check
  332. // Compute distance from the frustum
  333. const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::NEAR];
  334. const F32 distFromFrustum = max(0.0f, testPlane(nearPlane, spatialc->getAabbWorldSpace()));
  335. castsShadow = distFromFrustum < primaryFrc.getEffectiveShadowDistance();
  336. }
  337. switch(lc->getLightComponentType())
  338. {
  339. case LightComponentType::POINT:
  340. {
  341. PointLightQueueElement* el = result.m_pointLights.newElement(alloc);
  342. lc->setupPointLightQueueElement(*el);
  343. if(castsShadow
  344. && !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::POINT_LIGHT_SHADOWS_ENABLED))
  345. {
  346. RenderQueue* a = alloc.newArray<RenderQueue>(6);
  347. nextQueues = WeakArray<RenderQueue>(a, 6);
  348. el->m_shadowRenderQueues[0] = &nextQueues[0];
  349. el->m_shadowRenderQueues[1] = &nextQueues[1];
  350. el->m_shadowRenderQueues[2] = &nextQueues[2];
  351. el->m_shadowRenderQueues[3] = &nextQueues[3];
  352. el->m_shadowRenderQueues[4] = &nextQueues[4];
  353. el->m_shadowRenderQueues[5] = &nextQueues[5];
  354. }
  355. else
  356. {
  357. zeroMemory(el->m_shadowRenderQueues);
  358. }
  359. break;
  360. }
  361. case LightComponentType::SPOT:
  362. {
  363. SpotLightQueueElement* el = result.m_spotLights.newElement(alloc);
  364. lc->setupSpotLightQueueElement(*el);
  365. if(castsShadow
  366. && !!(enabledVisibilityTests & FrustumComponentVisibilityTestFlag::SPOT_LIGHT_SHADOWS_ENABLED))
  367. {
  368. RenderQueue* a = alloc.newInstance<RenderQueue>();
  369. nextQueues = WeakArray<RenderQueue>(a, 1);
  370. el->m_shadowRenderQueue = a;
  371. }
  372. else
  373. {
  374. el->m_shadowRenderQueue = nullptr;
  375. }
  376. break;
  377. }
  378. case LightComponentType::DIRECTIONAL:
  379. {
  380. ANKI_ASSERT(lc->getShadowEnabled() == true && "Only with shadow for now");
  381. U32 cascadeCount;
  382. if(ANKI_UNLIKELY(!castsShadow))
  383. {
  384. cascadeCount = 0;
  385. }
  386. else if(!!(enabledVisibilityTests
  387. & FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_1_CASCADE))
  388. {
  389. cascadeCount = 1;
  390. }
  391. else
  392. {
  393. ANKI_ASSERT(!!(enabledVisibilityTests
  394. & FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES));
  395. cascadeCount = MAX_SHADOW_CASCADES2;
  396. }
  397. ANKI_ASSERT(cascadeCount <= MAX_SHADOW_CASCADES2);
  398. // Create some dummy frustum components and initialize them
  399. WeakArray<FrustumComponent> cascadeFrustumComponents(
  400. (cascadeCount) ? reinterpret_cast<FrustumComponent*>(
  401. alloc.allocate(cascadeCount * sizeof(FrustumComponent), alignof(FrustumComponent)))
  402. : nullptr,
  403. cascadeCount);
  404. for(U32 i = 0; i < cascadeCount; ++i)
  405. {
  406. ::new(&cascadeFrustumComponents[i]) FrustumComponent(&node);
  407. cascadeFrustumComponents[i].setFrustumType(FrustumType::ORTHOGRAPHIC);
  408. }
  409. lc->setupDirectionalLightQueueElement(testedFrc, result.m_directionalLight, cascadeFrustumComponents);
  410. nextQueues = WeakArray<RenderQueue>(
  411. (cascadeCount) ? alloc.newArray<RenderQueue>(cascadeCount) : nullptr, cascadeCount);
  412. for(U32 i = 0; i < cascadeCount; ++i)
  413. {
  414. result.m_directionalLight.m_shadowRenderQueues[i] = &nextQueues[i];
  415. }
  416. // Despite the fact that it's the same light it will have different properties if viewed by different
  417. // cameras. If the renderer finds the same UUID it will think it's cached and use wrong shadow tiles.
  418. // That's why we need to change its UUID and bind it to the frustum that is currently viewing the light
  419. result.m_directionalLight.m_uuid = testedNode.getUuid();
  420. // Manually update the dummy components
  421. for(U32 i = 0; i < cascadeCount; ++i)
  422. {
  423. cascadeFrustumComponents[i].setEnabledVisibilityTests(
  424. FrustumComponentVisibilityTestFlag::SHADOW_CASTERS);
  425. Bool updated;
  426. Error err = cascadeFrustumComponents[i].update(node, 0.0f, 1.0f, updated);
  427. ANKI_ASSERT(updated == true && !err);
  428. (void)err;
  429. (void)updated;
  430. }
  431. nextQueueFrustumComponents = cascadeFrustumComponents;
  432. break;
  433. }
  434. default:
  435. ANKI_ASSERT(0);
  436. }
  437. }
  438. if(lfc && lfc->isLoaded())
  439. {
  440. LensFlareQueueElement* el = result.m_lensFlares.newElement(alloc);
  441. lfc->setupLensFlareQueueElement(*el);
  442. }
  443. if(reflc)
  444. {
  445. ReflectionProbeQueueElement* el = result.m_reflectionProbes.newElement(alloc);
  446. reflc->setupReflectionProbeQueueElement(*el);
  447. if(reflc->getMarkedForRendering())
  448. {
  449. RenderQueue* a = alloc.newArray<RenderQueue>(6);
  450. nextQueues = WeakArray<RenderQueue>(a, 6);
  451. el->m_renderQueues[0] = &nextQueues[0];
  452. el->m_renderQueues[1] = &nextQueues[1];
  453. el->m_renderQueues[2] = &nextQueues[2];
  454. el->m_renderQueues[3] = &nextQueues[3];
  455. el->m_renderQueues[4] = &nextQueues[4];
  456. el->m_renderQueues[5] = &nextQueues[5];
  457. }
  458. else
  459. {
  460. el->m_renderQueues = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
  461. }
  462. }
  463. if(decalc)
  464. {
  465. DecalQueueElement* el = result.m_decals.newElement(alloc);
  466. decalc->setupDecalQueueElement(*el);
  467. }
  468. if(fogc)
  469. {
  470. FogDensityQueueElement* el = result.m_fogDensityVolumes.newElement(alloc);
  471. fogc->setupFogDensityQueueElement(*el);
  472. }
  473. if(giprobec)
  474. {
  475. GlobalIlluminationProbeQueueElement* el = result.m_giProbes.newElement(alloc);
  476. giprobec->setupGlobalIlluminationProbeQueueElement(*el);
  477. if(giprobec->getMarkedForRendering())
  478. {
  479. RenderQueue* a = alloc.newArray<RenderQueue>(6);
  480. nextQueues = WeakArray<RenderQueue>(a, 6);
  481. el->m_renderQueues[0] = &nextQueues[0];
  482. el->m_renderQueues[1] = &nextQueues[1];
  483. el->m_renderQueues[2] = &nextQueues[2];
  484. el->m_renderQueues[3] = &nextQueues[3];
  485. el->m_renderQueues[4] = &nextQueues[4];
  486. el->m_renderQueues[5] = &nextQueues[5];
  487. }
  488. else
  489. {
  490. el->m_renderQueues = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
  491. }
  492. }
  493. if(computec)
  494. {
  495. GenericGpuComputeJobQueueElement* el = result.m_genericGpuComputeJobs.newElement(alloc);
  496. computec->setupGenericGpuComputeJobQueueElement(*el);
  497. }
  498. if(uic)
  499. {
  500. UiQueueElement* el = result.m_uis.newElement(alloc);
  501. uic->setupUiQueueElement(*el);
  502. }
  503. // Add more frustums to the list
  504. if(nextQueues.getSize() > 0)
  505. {
  506. U32 count = 0;
  507. if(ANKI_LIKELY(nextQueueFrustumComponents.getSize() == 0))
  508. {
  509. node.iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& frc) {
  510. m_frcCtx->m_visCtx->submitNewWork(frc, primaryFrc, nextQueues[count++], hive);
  511. });
  512. }
  513. else
  514. {
  515. for(FrustumComponent& frc : nextQueueFrustumComponents)
  516. {
  517. m_frcCtx->m_visCtx->submitNewWork(frc, primaryFrc, nextQueues[count++], hive);
  518. }
  519. }
  520. }
  521. // Update timestamp
  522. timestamp = max(timestamp, node.getComponentMaxTimestamp());
  523. } // end for
  524. }
  525. void CombineResultsTask::combine()
  526. {
  527. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_COMBINE_RESULTS);
  528. auto alloc = m_frcCtx->m_visCtx->m_scene->getFrameAllocator();
  529. RenderQueue& results = *m_frcCtx->m_renderQueue;
  530. // Compute the timestamp
  531. const U32 threadCount = m_frcCtx->m_queueViews.getSize();
  532. results.m_shadowRenderablesLastUpdateTimestamp = 0;
  533. for(U32 i = 0; i < threadCount; ++i)
  534. {
  535. results.m_shadowRenderablesLastUpdateTimestamp =
  536. max(results.m_shadowRenderablesLastUpdateTimestamp, m_frcCtx->m_queueViews[i].m_timestamp);
  537. }
  538. ANKI_ASSERT(results.m_shadowRenderablesLastUpdateTimestamp);
  539. #define ANKI_VIS_COMBINE(t_, member_) \
  540. { \
  541. Array<TRenderQueueElementStorage<t_>, 64> subStorages; \
  542. for(U32 i = 0; i < threadCount; ++i) \
  543. { \
  544. subStorages[i] = m_frcCtx->m_queueViews[i].member_; \
  545. } \
  546. combineQueueElements<t_>(alloc, WeakArray<TRenderQueueElementStorage<t_>>(&subStorages[0], threadCount), \
  547. nullptr, results.member_, nullptr); \
  548. }
  549. ANKI_VIS_COMBINE(RenderableQueueElement, m_renderables);
  550. ANKI_VIS_COMBINE(RenderableQueueElement, m_earlyZRenderables);
  551. ANKI_VIS_COMBINE(RenderableQueueElement, m_forwardShadingRenderables);
  552. ANKI_VIS_COMBINE(PointLightQueueElement, m_pointLights);
  553. ANKI_VIS_COMBINE(SpotLightQueueElement, m_spotLights);
  554. ANKI_VIS_COMBINE(ReflectionProbeQueueElement, m_reflectionProbes);
  555. ANKI_VIS_COMBINE(LensFlareQueueElement, m_lensFlares);
  556. ANKI_VIS_COMBINE(DecalQueueElement, m_decals);
  557. ANKI_VIS_COMBINE(FogDensityQueueElement, m_fogDensityVolumes);
  558. ANKI_VIS_COMBINE(GlobalIlluminationProbeQueueElement, m_giProbes);
  559. ANKI_VIS_COMBINE(GenericGpuComputeJobQueueElement, m_genericGpuComputeJobs);
  560. ANKI_VIS_COMBINE(RayTracingInstanceQueueElement, m_rayTracingInstances);
  561. ANKI_VIS_COMBINE(UiQueueElement, m_uis);
  562. for(U32 i = 0; i < threadCount; ++i)
  563. {
  564. if(m_frcCtx->m_queueViews[i].m_directionalLight.m_uuid != 0)
  565. {
  566. results.m_directionalLight = m_frcCtx->m_queueViews[i].m_directionalLight;
  567. }
  568. }
  569. #undef ANKI_VIS_COMBINE
  570. const Bool isShadowFrustum =
  571. !!(m_frcCtx->m_frc->getEnabledVisibilityTests() & FrustumComponentVisibilityTestFlag::SHADOW_CASTERS);
  572. // Sort some of the arrays
  573. if(!isShadowFrustum)
  574. {
  575. std::sort(results.m_renderables.getBegin(), results.m_renderables.getEnd(), MaterialDistanceSortFunctor());
  576. std::sort(results.m_earlyZRenderables.getBegin(), results.m_earlyZRenderables.getEnd(),
  577. DistanceSortFunctor<RenderableQueueElement>());
  578. std::sort(results.m_forwardShadingRenderables.getBegin(), results.m_forwardShadingRenderables.getEnd(),
  579. RevDistanceSortFunctor<RenderableQueueElement>());
  580. }
  581. std::sort(results.m_giProbes.getBegin(), results.m_giProbes.getEnd());
  582. // Sort the ligths as well because some rendering effects expect the same order from frame to frame
  583. std::sort(results.m_pointLights.getBegin(), results.m_pointLights.getEnd(),
  584. [](const PointLightQueueElement& a, const PointLightQueueElement& b) -> Bool {
  585. if(a.hasShadow() != b.hasShadow())
  586. {
  587. return a.hasShadow() < b.hasShadow();
  588. }
  589. else
  590. {
  591. return a.m_uuid < b.m_uuid;
  592. }
  593. });
  594. std::sort(results.m_spotLights.getBegin(), results.m_spotLights.getEnd(),
  595. [](const SpotLightQueueElement& a, const SpotLightQueueElement& b) -> Bool {
  596. if(a.hasShadow() != b.hasShadow())
  597. {
  598. return a.hasShadow() > b.hasShadow();
  599. }
  600. else
  601. {
  602. return a.m_uuid < b.m_uuid;
  603. }
  604. });
  605. // Cleanup
  606. if(m_frcCtx->m_r)
  607. {
  608. m_frcCtx->m_r->~SoftwareRasterizer();
  609. }
  610. }
  611. template<typename T>
  612. void CombineResultsTask::combineQueueElements(SceneFrameAllocator<U8>& alloc,
  613. WeakArray<TRenderQueueElementStorage<T>> subStorages,
  614. WeakArray<TRenderQueueElementStorage<U32>>* ptrSubStorages,
  615. WeakArray<T>& combined, WeakArray<T*>* ptrCombined)
  616. {
  617. U32 totalElCount = subStorages[0].m_elementCount;
  618. U32 biggestSubStorageIdx = 0;
  619. for(U32 i = 1; i < subStorages.getSize(); ++i)
  620. {
  621. totalElCount += subStorages[i].m_elementCount;
  622. if(subStorages[i].m_elementStorage > subStorages[biggestSubStorageIdx].m_elementStorage)
  623. {
  624. biggestSubStorageIdx = i;
  625. }
  626. }
  627. if(totalElCount == 0)
  628. {
  629. return;
  630. }
  631. // Count ptrSubStorage elements
  632. T** ptrIt = nullptr;
  633. if(ptrSubStorages != nullptr)
  634. {
  635. ANKI_ASSERT(ptrCombined);
  636. U32 ptrTotalElCount = (*ptrSubStorages)[0].m_elementCount;
  637. for(U32 i = 1; i < ptrSubStorages->getSize(); ++i)
  638. {
  639. ptrTotalElCount += (*ptrSubStorages)[i].m_elementCount;
  640. }
  641. // Create the new storage
  642. if(ptrTotalElCount > 0)
  643. {
  644. ptrIt = alloc.newArray<T*>(ptrTotalElCount);
  645. *ptrCombined = WeakArray<T*>(ptrIt, ptrTotalElCount);
  646. }
  647. }
  648. T* it;
  649. if(totalElCount > subStorages[biggestSubStorageIdx].m_elementStorage)
  650. {
  651. // Can't reuse any of the existing storage, will allocate a brand new one
  652. it = alloc.newArray<T>(totalElCount);
  653. biggestSubStorageIdx = MAX_U32;
  654. combined = WeakArray<T>(it, totalElCount);
  655. }
  656. else
  657. {
  658. // Will reuse existing storage
  659. it = subStorages[biggestSubStorageIdx].m_elements + subStorages[biggestSubStorageIdx].m_elementCount;
  660. combined = WeakArray<T>(subStorages[biggestSubStorageIdx].m_elements, totalElCount);
  661. }
  662. for(U32 i = 0; i < subStorages.getSize(); ++i)
  663. {
  664. if(subStorages[i].m_elementCount == 0)
  665. {
  666. continue;
  667. }
  668. // Copy the pointers
  669. if(ptrIt)
  670. {
  671. T* base = (i != biggestSubStorageIdx) ? it : subStorages[biggestSubStorageIdx].m_elements;
  672. for(U32 x = 0; x < (*ptrSubStorages)[i].m_elementCount; ++x)
  673. {
  674. ANKI_ASSERT((*ptrSubStorages)[i].m_elements[x] < subStorages[i].m_elementCount);
  675. *ptrIt = base + (*ptrSubStorages)[i].m_elements[x];
  676. ++ptrIt;
  677. }
  678. ANKI_ASSERT(ptrIt <= ptrCombined->getEnd());
  679. }
  680. // Copy the elements
  681. if(i != biggestSubStorageIdx)
  682. {
  683. memcpy(it, subStorages[i].m_elements, sizeof(T) * subStorages[i].m_elementCount);
  684. it += subStorages[i].m_elementCount;
  685. }
  686. }
  687. }
  688. void SceneGraph::doVisibilityTests(SceneNode& fsn, SceneGraph& scene, RenderQueue& rqueue)
  689. {
  690. ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_TESTS);
  691. ThreadHive& hive = scene.getThreadHive();
  692. VisibilityContext ctx;
  693. ctx.m_scene = &scene;
  694. ctx.m_earlyZDist = scene.getConfig().m_earlyZDistance;
  695. const FrustumComponent& mainFrustum = fsn.getFirstComponentOfType<FrustumComponent>();
  696. ctx.submitNewWork(mainFrustum, mainFrustum, rqueue, hive);
  697. const FrustumComponent* extendedFrustum = fsn.tryGetNthComponentOfType<FrustumComponent>(1);
  698. if(extendedFrustum)
  699. {
  700. // This is the frustum for RT.
  701. ANKI_ASSERT(
  702. !(extendedFrustum->getEnabledVisibilityTests() & ~FrustumComponentVisibilityTestFlag::ALL_RAY_TRACING));
  703. rqueue.m_rayTracingQueue = scene.getFrameAllocator().newInstance<RenderQueue>();
  704. ctx.submitNewWork(*extendedFrustum, mainFrustum, *rqueue.m_rayTracingQueue, hive);
  705. }
  706. hive.waitAllTasks();
  707. ctx.m_testedFrcs.destroy(scene.getFrameAllocator());
  708. }
  709. } // end namespace anki