Visibility.cpp 26 KB

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