Is.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. #include "anki/renderer/Is.h"
  2. #include "anki/renderer/Renderer.h"
  3. #include "anki/scene/SceneGraph.h"
  4. #include "anki/scene/Camera.h"
  5. #include "anki/scene/Light.h"
  6. #include "anki/core/ThreadPool.h"
  7. namespace anki {
  8. //==============================================================================
  9. // Consts
  10. static const U MAX_POINT_LIGHTS_PER_TILE =
  11. ANKI_RENDERER_MAX_POINT_LIGHTS_PER_TILE;
  12. static const U MAX_SPOT_LIGHTS_PER_TILE =
  13. ANKI_RENDERER_MAX_SPOT_LIGHTS_PER_TILE;
  14. static const U MAX_SPOT_TEX_LIGHTS_PER_TILE =
  15. ANKI_RENDERER_MAX_SPOT_TEX_LIGHTS_PER_TILE;
  16. static const U MAX_POINT_LIGHTS = ANKI_RENDERER_MAX_POINT_LIGHTS;
  17. static const U MAX_SPOT_LIGHTS = ANKI_RENDERER_MAX_SPOT_LIGHTS;
  18. static const U MAX_SPOT_TEX_LIGHTS = ANKI_RENDERER_MAX_SPOT_TEX_LIGHTS;
  19. static const U MAX_LIGHTS =
  20. MAX_POINT_LIGHTS + MAX_SPOT_LIGHTS + MAX_SPOT_TEX_LIGHTS;
  21. static const U TILES_X_COUNT = ANKI_RENDERER_TILES_X_COUNT;
  22. static const U TILES_Y_COUNT = ANKI_RENDERER_TILES_Y_COUNT;
  23. static const U TILES_COUNT = TILES_X_COUNT * TILES_Y_COUNT;
  24. //==============================================================================
  25. /// Check if the prev ground light vector is almost equal to the current
  26. static Bool groundVectorsEqual(const Vec3& prev, const Vec3& crnt)
  27. {
  28. Bool out = true;
  29. for(U i = 0; i < 3; i++)
  30. {
  31. Bool subout = fabs(prev[i] - crnt[i]) < (getEpsilon<F32>() * 10.0);
  32. out = out && subout;
  33. }
  34. return out;
  35. }
  36. //==============================================================================
  37. /// Clamp a value
  38. template<typename T, typename Y>
  39. void clamp(T& in, Y limit)
  40. {
  41. in = std::min(in, (T)limit);
  42. }
  43. //==============================================================================
  44. // Shader structs and block representations. All positions and directions in
  45. // viewspace
  46. // For documentation see the shaders
  47. namespace shader {
  48. struct Tile
  49. {
  50. Array<U32, 4> lightsCount;
  51. Array<U32, MAX_POINT_LIGHTS_PER_TILE> pointLightIndices;
  52. Array<U32, MAX_SPOT_LIGHTS_PER_TILE> spotLightIndices;
  53. Array<U32, MAX_SPOT_TEX_LIGHTS_PER_TILE> spotTexLightIndices;
  54. };
  55. struct Tiles
  56. {
  57. Array<Array<Tile, TILES_X_COUNT>, TILES_Y_COUNT> tiles;
  58. };
  59. struct Light
  60. {
  61. Vec4 posRadius;
  62. Vec4 diffuseColorShadowmapId;
  63. Vec4 specularColorTexId;
  64. };
  65. struct PointLight: Light
  66. {};
  67. struct SpotLight: Light
  68. {
  69. Vec4 lightDir;
  70. Vec4 outerCosInnerCos;
  71. Array<Vec4, 4> extendPoints;
  72. };
  73. struct SpotTexLight: SpotLight
  74. {
  75. Mat4 texProjectionMat; ///< Texture projection matrix
  76. };
  77. struct CommonUniforms
  78. {
  79. Vec4 planes;
  80. Vec4 sceneAmbientColor;
  81. Vec4 groundLightDir;
  82. };
  83. } // end namespace shader
  84. //==============================================================================
  85. static const PtrSize MIN_LIGHTS_UBO_SIZE =
  86. MAX_POINT_LIGHTS * sizeof(shader::PointLight)
  87. + MAX_SPOT_LIGHTS * sizeof(shader::SpotLight)
  88. + MAX_SPOT_TEX_LIGHTS * sizeof(shader::SpotTexLight);
  89. /// Align everything to make UBOs happy
  90. static PtrSize calcLigthsUboSize()
  91. {
  92. PtrSize size;
  93. PtrSize uboAlignment = BufferObject::getUniformBufferOffsetAlignment();
  94. size = alignSizeRoundUp(
  95. uboAlignment,
  96. MAX_POINT_LIGHTS * sizeof(shader::PointLight));
  97. size += alignSizeRoundUp(
  98. uboAlignment,
  99. MAX_SPOT_LIGHTS * sizeof(shader::SpotLight));
  100. size += alignSizeRoundUp(
  101. uboAlignment,
  102. MAX_SPOT_TEX_LIGHTS * sizeof(shader::SpotTexLight));
  103. return size;
  104. }
  105. //==============================================================================
  106. // Use compute shaders on GL >= 4.3
  107. static Bool useCompute()
  108. {
  109. return GlStateCommonSingleton::get().getMajorVersion() >= 4
  110. && GlStateCommonSingleton::get().getMinorVersion() >= 3
  111. && false;
  112. }
  113. //==============================================================================
  114. /// Write the lights to a client buffer
  115. struct WriteLightsJob: ThreadJob
  116. {
  117. shader::PointLight* pointLights = nullptr;
  118. shader::SpotLight* spotLights = nullptr;
  119. shader::SpotTexLight* spotTexLights = nullptr;
  120. shader::Tiles* tiles = nullptr;
  121. VisibilityTestResults::Container::const_iterator lightsBegin;
  122. VisibilityTestResults::Container::const_iterator lightsEnd;
  123. std::atomic<U32>* pointLightsCount = nullptr;
  124. std::atomic<U32>* spotLightsCount = nullptr;
  125. std::atomic<U32>* spotTexLightsCount = nullptr;
  126. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>*
  127. tilePointLightsCount = nullptr;
  128. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>*
  129. tileSpotLightsCount = nullptr;
  130. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>*
  131. tileSpotTexLightsCount = nullptr;
  132. Tiler* tiler = nullptr;
  133. Is* is = nullptr;
  134. /// Bin ligths on CPU path
  135. Bool binLights = true;
  136. void operator()(U threadId, U threadsCount)
  137. {
  138. U ligthsCount = lightsEnd - lightsBegin;
  139. // Count job bounds
  140. U64 start, end;
  141. choseStartEnd(threadId, threadsCount, ligthsCount, start, end);
  142. // Run all lights
  143. for(U64 i = start; i < end; i++)
  144. {
  145. const SceneNode* snode = (*(lightsBegin + i)).node;
  146. const Light* light = snode->getLight();
  147. ANKI_ASSERT(light);
  148. switch(light->getLightType())
  149. {
  150. case Light::LT_POINT:
  151. {
  152. const PointLight& l =
  153. *static_cast<const PointLight*>(light);
  154. I pos = doLight(l);
  155. if(binLights && pos != -1)
  156. {
  157. binLight(l, pos);
  158. }
  159. }
  160. break;
  161. case Light::LT_SPOT:
  162. {
  163. const SpotLight& l =
  164. *static_cast<const SpotLight*>(light);
  165. I pos = doLight(l);
  166. if(binLights && pos != -1)
  167. {
  168. binLight(l, pos);
  169. }
  170. }
  171. break;
  172. default:
  173. ANKI_ASSERT(0);
  174. break;
  175. }
  176. }
  177. }
  178. /// Copy CPU light to GPU buffer
  179. I doLight(const PointLight& light)
  180. {
  181. // Get GPU light
  182. I i = pointLightsCount->fetch_add(1);
  183. if(i >= (I)MAX_POINT_LIGHTS)
  184. {
  185. return -1;
  186. }
  187. shader::PointLight& slight = pointLights[i];
  188. const Camera* cam = is->cam;
  189. ANKI_ASSERT(cam);
  190. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  191. cam->getViewMatrix());
  192. slight.posRadius = Vec4(pos, -1.0 / light.getRadius());
  193. slight.diffuseColorShadowmapId = light.getDiffuseColor();
  194. slight.specularColorTexId = light.getSpecularColor();
  195. return i;
  196. }
  197. /// Copy CPU spot light to GPU buffer
  198. I doLight(const SpotLight& light)
  199. {
  200. const Camera* cam = is->cam;
  201. Bool isTexLight = light.getShadowEnabled();
  202. I i;
  203. shader::SpotLight* baseslight = nullptr;
  204. if(isTexLight)
  205. {
  206. // Spot tex light
  207. i = spotTexLightsCount->fetch_add(1);
  208. if(i >= (I)MAX_SPOT_TEX_LIGHTS)
  209. {
  210. return -1;
  211. }
  212. shader::SpotTexLight& slight = spotTexLights[i];
  213. baseslight = &slight;
  214. // Write matrix
  215. static const Mat4 biasMat4(
  216. 0.5, 0.0, 0.0, 0.5,
  217. 0.0, 0.5, 0.0, 0.5,
  218. 0.0, 0.0, 0.5, 0.5,
  219. 0.0, 0.0, 0.0, 1.0);
  220. // bias * proj_l * view_l * world_c
  221. slight.texProjectionMat = biasMat4 * light.getProjectionMatrix() *
  222. Mat4::combineTransformations(light.getViewMatrix(),
  223. Mat4(cam->getWorldTransform()));
  224. // Transpose because of driver bug
  225. slight.texProjectionMat.transpose();
  226. }
  227. else
  228. {
  229. // Spot light without texture
  230. i = spotLightsCount->fetch_add(1);
  231. if(i >= (I)MAX_SPOT_LIGHTS)
  232. {
  233. return -1;
  234. }
  235. shader::SpotLight& slight = spotLights[i];
  236. baseslight = &slight;
  237. }
  238. // Write common stuff
  239. ANKI_ASSERT(baseslight);
  240. // Pos & dist
  241. Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
  242. cam->getViewMatrix());
  243. baseslight->posRadius = Vec4(pos, -1.0 / light.getDistance());
  244. // Diff color and shadowmap ID now
  245. baseslight->diffuseColorShadowmapId =
  246. Vec4(light.getDiffuseColor().xyz(), (F32)light.getShadowMapIndex());
  247. // Spec color
  248. baseslight->specularColorTexId = light.getSpecularColor();
  249. // Light dir
  250. Vec3 lightDir = -light.getWorldTransform().getRotation().getZAxis();
  251. lightDir = cam->getViewMatrix().getRotationPart() * lightDir;
  252. baseslight->lightDir = Vec4(lightDir, 0.0);
  253. // Angles
  254. baseslight->outerCosInnerCos = Vec4(
  255. light.getOuterAngleCos(),
  256. light.getInnerAngleCos(),
  257. 1.0,
  258. 1.0);
  259. // extend points
  260. const PerspectiveFrustum& frustum = light.getFrustum();
  261. for(U i = 0; i < 4; i++)
  262. {
  263. Vec3 extendPoint = light.getWorldTransform().getOrigin()
  264. + frustum.getDirections()[i];
  265. extendPoint.transform(cam->getViewMatrix());
  266. baseslight->extendPoints[i] = Vec4(extendPoint, 1.0);
  267. }
  268. return i;
  269. }
  270. // Bin point light
  271. void binLight(const PointLight& light, U pos)
  272. {
  273. // Do the tests
  274. Tiler::Bitset bitset;
  275. tiler->test(light.getSpatialCollisionShape(), true, &bitset);
  276. // Bin to the correct tiles
  277. for(U t = 0; t < TILES_COUNT; t++)
  278. {
  279. // If not in tile bye
  280. if(!bitset.test(t))
  281. {
  282. continue;
  283. }
  284. U x = t % TILES_X_COUNT;
  285. U y = t / TILES_X_COUNT;
  286. U tilePos = (*tilePointLightsCount)[y][x].fetch_add(1);
  287. if(tilePos < MAX_POINT_LIGHTS_PER_TILE)
  288. {
  289. tiles->tiles[y][x].pointLightIndices[tilePos] = pos;
  290. }
  291. }
  292. }
  293. // Bin spot light
  294. void binLight(const SpotLight& light, U pos)
  295. {
  296. // Do the tests
  297. Tiler::Bitset bitset;
  298. tiler->test(light.getSpatialCollisionShape(), true, &bitset);
  299. // Bin to the correct tiles
  300. for(U t = 0; t < TILES_COUNT; t++)
  301. {
  302. // If not in tile bye
  303. if(!bitset.test(t))
  304. {
  305. continue;
  306. }
  307. U x = t % TILES_X_COUNT;
  308. U y = t / TILES_X_COUNT;
  309. if(light.getShadowEnabled())
  310. {
  311. U tilePos = (*tileSpotTexLightsCount)[y][x].fetch_add(1);
  312. if(tilePos < MAX_SPOT_TEX_LIGHTS_PER_TILE)
  313. {
  314. tiles->tiles[y][x].spotTexLightIndices[tilePos] = pos;
  315. }
  316. }
  317. else
  318. {
  319. U tilePos = (*tileSpotLightsCount)[y][x].fetch_add(1);
  320. if(tilePos < MAX_SPOT_LIGHTS_PER_TILE)
  321. {
  322. tiles->tiles[y][x].spotLightIndices[tilePos] = pos;
  323. }
  324. }
  325. }
  326. }
  327. };
  328. //==============================================================================
  329. Is::Is(Renderer* r_)
  330. : RenderingPass(r_), sm(r_)
  331. {}
  332. //==============================================================================
  333. Is::~Is()
  334. {}
  335. //==============================================================================
  336. void Is::init(const RendererInitializer& initializer)
  337. {
  338. try
  339. {
  340. initInternal(initializer);
  341. }
  342. catch(const std::exception& e)
  343. {
  344. throw ANKI_EXCEPTION("Failed to init IS") << e;
  345. }
  346. }
  347. //==============================================================================
  348. void Is::initInternal(const RendererInitializer& initializer)
  349. {
  350. groundLightEnabled = initializer.is.groundLightEnabled;
  351. //
  352. // Init the passes
  353. //
  354. sm.init(initializer);
  355. //
  356. // Load the programs
  357. //
  358. std::stringstream pps;
  359. pps << "#define TILES_X_COUNT " << TILES_X_COUNT << "\n"
  360. << "#define TILES_Y_COUNT " << TILES_Y_COUNT << "\n"
  361. << "#define TILES_COUNT " << TILES_COUNT << "\n"
  362. << "#define RENDERER_WIDTH " << r->getWidth() << "\n"
  363. << "#define RENDERER_HEIGHT " << r->getHeight() << "\n"
  364. << "#define MAX_POINT_LIGHTS_PER_TILE " << MAX_POINT_LIGHTS_PER_TILE
  365. << "\n"
  366. << "#define MAX_SPOT_LIGHTS_PER_TILE " << MAX_SPOT_LIGHTS_PER_TILE
  367. << "\n"
  368. << "#define MAX_SPOT_TEX_LIGHTS_PER_TILE "
  369. << MAX_SPOT_TEX_LIGHTS_PER_TILE << "\n"
  370. << "#define MAX_POINT_LIGHTS " << MAX_POINT_LIGHTS << "\n"
  371. << "#define MAX_SPOT_LIGHTS " << MAX_SPOT_LIGHTS << "\n"
  372. << "#define MAX_SPOT_TEX_LIGHTS " << MAX_SPOT_TEX_LIGHTS << "\n"
  373. << "#define GROUND_LIGHT " << groundLightEnabled << "\n"
  374. << "#define USE_MRT " << ANKI_RENDERER_USE_MRT << "\n";
  375. if(sm.getPcfEnabled())
  376. {
  377. pps << "#define PCF 1\n";
  378. }
  379. else
  380. {
  381. pps << "#define PCF 0\n";
  382. }
  383. // point light
  384. lightPassProg.load(ShaderProgramResource::createSrcCodeToCache(
  385. "shaders/IsLp.glsl", pps.str().c_str()).c_str());
  386. #if ANKI_GL == ANKI_GL_DESKTOP
  387. if(useCompute())
  388. {
  389. pps << "#define DEPTHMAP_WIDTH "
  390. << (r->getMs().getDepthFai().getWidth()) << "\n"
  391. << "#define DEPTHMAP_HEIGHT "
  392. << (r->getMs().getDepthFai().getHeight()) << "\n"
  393. << "#define TILES_BLOCK_BINDING "
  394. << TILES_BLOCK_BINDING << "\n";
  395. rejectProg.load(ShaderProgramResource::createSrcCodeToCache(
  396. "shaders/IsRejectLights.glsl", pps.str().c_str()).c_str());
  397. }
  398. #endif
  399. //
  400. // Create FBOs
  401. //
  402. // IS FBO
  403. fai.create2dFai(r->getWidth(), r->getHeight(), GL_RGB8,
  404. GL_RGB, GL_UNSIGNED_BYTE);
  405. fbo.create();
  406. fbo.setColorAttachments({&fai});
  407. fbo.setOtherAttachment(GL_DEPTH_ATTACHMENT, r->getMs().getDepthFai());
  408. if(!fbo.isComplete())
  409. {
  410. throw ANKI_EXCEPTION("Fbo not complete");
  411. }
  412. //
  413. // Init the quad
  414. //
  415. static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {0.0, 1.0},
  416. {1.0, 0.0}, {0.0, 0.0}};
  417. quadPositionsVbo.create(GL_ARRAY_BUFFER, sizeof(quadVertCoords),
  418. quadVertCoords, GL_STATIC_DRAW);
  419. quadVao.create();
  420. quadVao.attachArrayBufferVbo(
  421. &quadPositionsVbo, 0, 2, GL_FLOAT, false, 0, 0);
  422. //
  423. // Create UBOs
  424. //
  425. // Common UBO
  426. commonUbo.create(sizeof(shader::CommonUniforms), nullptr);
  427. // lights UBO
  428. lightsUbo.create(calcLigthsUboSize(), nullptr);
  429. uboAlignment = BufferObject::getUniformBufferOffsetAlignment();
  430. // tiles BO
  431. tilesBuffer.create(
  432. GL_UNIFORM_BUFFER,
  433. sizeof(shader::Tiles),
  434. nullptr,
  435. GL_DYNAMIC_DRAW);
  436. ANKI_LOGI("Creating BOs: lights: " << calcLigthsUboSize() << "B tiles: "
  437. << sizeof(shader::Tiles) << "B");
  438. // Sanity checks
  439. const ShaderProgramUniformBlock* ublock;
  440. ublock = &lightPassProg->findUniformBlock("commonBlock");
  441. ublock->setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  442. if(ublock->getSize() != sizeof(shader::CommonUniforms)
  443. || ublock->getBinding() != COMMON_UNIFORMS_BLOCK_BINDING)
  444. {
  445. throw ANKI_EXCEPTION("Problem with the commonBlock");
  446. }
  447. #if ANKI_GL == ANKI_GL_DESKTOP
  448. if(rejectProg.isLoaded())
  449. {
  450. ublock = &rejectProg->findUniformBlock("commonBlock");
  451. ublock->setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  452. if(ublock->getSize() != sizeof(shader::CommonUniforms)
  453. || ublock->getBinding() != COMMON_UNIFORMS_BLOCK_BINDING)
  454. {
  455. throw ANKI_EXCEPTION("Problem with the commonBlock");
  456. }
  457. }
  458. #endif
  459. ublock = &lightPassProg->findUniformBlock("pointLightsBlock");
  460. ublock->setBinding(POINT_LIGHTS_BLOCK_BINDING);
  461. if(ublock->getSize() != sizeof(shader::PointLight) * MAX_POINT_LIGHTS
  462. || ublock->getBinding() != POINT_LIGHTS_BLOCK_BINDING)
  463. {
  464. throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
  465. }
  466. #if ANKI_GL == ANKI_GL_DESKTOP
  467. if(rejectProg.isLoaded())
  468. {
  469. ublock = &rejectProg->findUniformBlock("pointLightsBlock");
  470. ublock->setBinding(POINT_LIGHTS_BLOCK_BINDING);
  471. if(ublock->getSize() != sizeof(shader::PointLight) * MAX_POINT_LIGHTS
  472. || ublock->getBinding() != POINT_LIGHTS_BLOCK_BINDING)
  473. {
  474. throw ANKI_EXCEPTION("Problem with the pointLightsBlock");
  475. }
  476. }
  477. #endif
  478. ublock = &lightPassProg->findUniformBlock("spotLightsBlock");
  479. ublock->setBinding(SPOT_LIGHTS_BLOCK_BINDING);
  480. if(ublock->getSize() != sizeof(shader::SpotLight) * MAX_SPOT_LIGHTS
  481. || ublock->getBinding() != SPOT_LIGHTS_BLOCK_BINDING)
  482. {
  483. throw ANKI_EXCEPTION("Problem with the spotLightsBlock");
  484. }
  485. ublock = &lightPassProg->findUniformBlock("spotTexLightsBlock");
  486. ublock->setBinding(SPOT_TEX_LIGHTS_BLOCK_BINDING);
  487. if(ublock->getSize() != sizeof(shader::SpotTexLight) * MAX_SPOT_TEX_LIGHTS
  488. || ublock->getBinding() != SPOT_TEX_LIGHTS_BLOCK_BINDING)
  489. {
  490. throw ANKI_EXCEPTION("Problem with the spotTexLightsBlock");
  491. }
  492. ublock = &lightPassProg->findUniformBlock("tilesBlock");
  493. ublock->setBinding(TILES_BLOCK_BINDING);
  494. if(ublock->getSize() != sizeof(shader::Tiles)
  495. || ublock->getBinding() != TILES_BLOCK_BINDING)
  496. {
  497. throw ANKI_EXCEPTION("Problem with the tilesBlock");
  498. }
  499. #if ANKI_GL == ANKI_GL_DESKTOP && 0
  500. if(rejectProg.isLoaded())
  501. {
  502. ublock = &rejectProg->findUniformBlock("tilesBlock");
  503. ublock->setBinding(TILES_BLOCK_BINDING);
  504. if(ublock->getSize() != sizeof(shader::Tiles)
  505. || ublock->getBinding() != TILES_BLOCK_BINDING)
  506. {
  507. throw ANKI_EXCEPTION("Problem with the tilesBlock");
  508. }
  509. }
  510. #endif
  511. }
  512. //==============================================================================
  513. void Is::lightPass()
  514. {
  515. ThreadPool& threadPool = ThreadPoolSingleton::get();
  516. VisibilityTestResults& vi =
  517. *cam->getFrustumable()->getVisibilityTestResults();
  518. //
  519. // Quickly get the lights
  520. //
  521. U visiblePointLightsCount = 0;
  522. U visibleSpotLightsCount = 0;
  523. U visibleSpotTexLightsCount = 0;
  524. Array<Light*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
  525. for(auto it = vi.getLightsBegin(); it != vi.getLightsEnd(); ++it)
  526. {
  527. Light* light = (*it).node->getLight();
  528. ANKI_ASSERT(light);
  529. switch(light->getLightType())
  530. {
  531. case Light::LT_POINT:
  532. // Use % to avoid overflows
  533. ++visiblePointLightsCount;
  534. break;
  535. case Light::LT_SPOT:
  536. {
  537. SpotLight* slight = static_cast<SpotLight*>(light);
  538. if(slight->getShadowEnabled())
  539. {
  540. shadowCasters[visibleSpotTexLightsCount++] = slight;
  541. }
  542. else
  543. {
  544. ++visibleSpotLightsCount;
  545. }
  546. break;
  547. }
  548. default:
  549. ANKI_ASSERT(0);
  550. break;
  551. }
  552. }
  553. // Sanitize the counters
  554. clamp(visiblePointLightsCount, MAX_POINT_LIGHTS);
  555. clamp(visibleSpotLightsCount, MAX_SPOT_LIGHTS);
  556. clamp(visibleSpotTexLightsCount, MAX_SPOT_TEX_LIGHTS);
  557. //
  558. // Do shadows pass
  559. //
  560. sm.run(&shadowCasters[0], visibleSpotTexLightsCount);
  561. //
  562. // Write the lights and tiles UBOs
  563. //
  564. // Get the offsets and sizes of each uniform block
  565. PtrSize pointLightsOffset = 0;
  566. PtrSize pointLightsSize =
  567. sizeof(shader::PointLight) * visiblePointLightsCount;
  568. pointLightsSize = alignSizeRoundUp(uboAlignment, pointLightsSize);
  569. PtrSize spotLightsOffset = pointLightsSize;
  570. PtrSize spotLightsSize =
  571. sizeof(shader::SpotLight) * visibleSpotLightsCount;
  572. spotLightsSize = alignSizeRoundUp(uboAlignment, spotLightsSize);
  573. PtrSize spotTexLightsOffset = spotLightsOffset + spotLightsSize;
  574. PtrSize spotTexLightsSize =
  575. sizeof(shader::SpotTexLight) * visibleSpotTexLightsCount;
  576. spotTexLightsSize = alignSizeRoundUp(uboAlignment, spotTexLightsSize);
  577. ANKI_ASSERT(spotTexLightsOffset + spotTexLightsSize <= calcLigthsUboSize());
  578. // Fire the super jobs
  579. Array<WriteLightsJob, ThreadPool::MAX_THREADS> jobs;
  580. U8 clientBuffer[MIN_LIGHTS_UBO_SIZE * 2]; // Aproximate size
  581. ANKI_ASSERT(MIN_LIGHTS_UBO_SIZE * 2 >= calcLigthsUboSize());
  582. shader::Tiles clientTiles;
  583. std::atomic<U32> pointLightsAtomicCount(0);
  584. std::atomic<U32> spotLightsAtomicCount(0);
  585. std::atomic<U32> spotTexLightsAtomicCount(0);
  586. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>
  587. tilePointLightsCount;
  588. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>
  589. tileSpotLightsCount;
  590. Array<Array<std::atomic<U32>, TILES_X_COUNT>, TILES_Y_COUNT>
  591. tileSpotTexLightsCount;
  592. for(U y = 0; y < TILES_Y_COUNT; y++)
  593. {
  594. for(U x = 0; x < TILES_X_COUNT; x++)
  595. {
  596. tilePointLightsCount[y][x].store(0);
  597. tileSpotLightsCount[y][x].store(0);
  598. tileSpotTexLightsCount[y][x].store(0);
  599. }
  600. }
  601. for(U i = 0; i < threadPool.getThreadsCount(); i++)
  602. {
  603. WriteLightsJob& job = jobs[i];
  604. job.pointLights =
  605. (shader::PointLight*)(&clientBuffer[0] + pointLightsOffset);
  606. job.spotLights =
  607. (shader::SpotLight*)(&clientBuffer[0] + spotLightsOffset);
  608. job.spotTexLights =
  609. (shader::SpotTexLight*)(&clientBuffer[0] + spotTexLightsOffset);
  610. job.tiles = &clientTiles;
  611. job.lightsBegin = vi.getLightsBegin();
  612. job.lightsEnd = vi.getLightsEnd();
  613. job.pointLightsCount = &pointLightsAtomicCount;
  614. job.spotLightsCount = &spotLightsAtomicCount;
  615. job.spotTexLightsCount = &spotTexLightsAtomicCount;
  616. job.tilePointLightsCount = &tilePointLightsCount;
  617. job.tileSpotLightsCount = &tileSpotLightsCount;
  618. job.tileSpotTexLightsCount = &tileSpotTexLightsCount;
  619. job.tiler = &r->getTiler();
  620. job.is = this;
  621. threadPool.assignNewJob(i, &job);
  622. }
  623. // In the meantime set the state
  624. setState();
  625. // Sync
  626. threadPool.waitForAllJobsToFinish();
  627. // Write the light count for each tile
  628. for(U y = 0; y < TILES_Y_COUNT; y++)
  629. {
  630. for(U x = 0; x < TILES_X_COUNT; x++)
  631. {
  632. clientTiles.tiles[y][x].lightsCount[0] =
  633. tilePointLightsCount[y][x].load();
  634. clamp(clientTiles.tiles[y][x].lightsCount[0],
  635. MAX_POINT_LIGHTS_PER_TILE);
  636. clientTiles.tiles[y][x].lightsCount[2] =
  637. tileSpotLightsCount[y][x].load();
  638. clamp(clientTiles.tiles[y][x].lightsCount[2],
  639. MAX_SPOT_LIGHTS_PER_TILE);
  640. clientTiles.tiles[y][x].lightsCount[3] =
  641. tileSpotTexLightsCount[y][x].load();
  642. clamp(clientTiles.tiles[y][x].lightsCount[3],
  643. MAX_SPOT_TEX_LIGHTS_PER_TILE);
  644. }
  645. }
  646. // Write BOs
  647. lightsUbo.write(
  648. &clientBuffer[0], 0, spotTexLightsOffset + spotTexLightsSize);
  649. tilesBuffer.write(&clientTiles);
  650. //
  651. // Reject occluded lights. This operation issues a compute job to reject
  652. // lights from the tiles
  653. //
  654. #if ANKI_GL == ANKI_GL_DESKTOP
  655. if(ANKI_UNLIKELY(rejectProg.isLoaded()))
  656. {
  657. rejectProg->bind();
  658. if(pointLightsSize > 0)
  659. {
  660. lightsUbo.setBindingRange(
  661. POINT_LIGHTS_BLOCK_BINDING, pointLightsOffset, pointLightsSize);
  662. }
  663. /*if(spotLightsSize > 0)
  664. {
  665. lightsUbo.setBindingRange(SPOT_LIGHTS_BLOCK_BINDING, spotLightsOffset,
  666. spotLightsSize);
  667. }
  668. if(spotTexLightsSize > 0)
  669. {
  670. lightsUbo.setBindingRange(SPOT_TEX_LIGHTS_BLOCK_BINDING,
  671. spotTexLightsOffset, spotTexLightsSize);
  672. }*/
  673. tilesBuffer.setTarget(GL_SHADER_STORAGE_BUFFER);
  674. tilesBuffer.setBinding(TILES_BLOCK_BINDING);
  675. commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  676. rejectProg->findUniformVariable("depthMap").set(
  677. r->getMs().getDepthFai());
  678. glDispatchCompute(TILES_X_COUNT, TILES_Y_COUNT, 1);
  679. tilesBuffer.setTarget(GL_UNIFORM_BUFFER);
  680. }
  681. #endif
  682. //
  683. // Setup shader and draw
  684. //
  685. // shader prog
  686. lightPassProg->bind();
  687. lightPassProg->findUniformVariable("limitsOfNearPlane").set(
  688. Vec4(r->getLimitsOfNearPlane(), r->getLimitsOfNearPlane2()));
  689. commonUbo.setBinding(COMMON_UNIFORMS_BLOCK_BINDING);
  690. if(pointLightsSize > 0)
  691. {
  692. lightsUbo.setBindingRange(POINT_LIGHTS_BLOCK_BINDING, pointLightsOffset,
  693. pointLightsSize);
  694. }
  695. if(spotLightsSize > 0)
  696. {
  697. lightsUbo.setBindingRange(SPOT_LIGHTS_BLOCK_BINDING, spotLightsOffset,
  698. spotLightsSize);
  699. }
  700. if(spotTexLightsSize > 0)
  701. {
  702. lightsUbo.setBindingRange(SPOT_TEX_LIGHTS_BLOCK_BINDING,
  703. spotTexLightsOffset, spotTexLightsSize);
  704. }
  705. tilesBuffer.setBinding(TILES_BLOCK_BINDING);
  706. lightPassProg->findUniformVariable("msFai0").set(r->getMs().getFai0());
  707. #if ANKI_RENDERER_USE_MRT
  708. lightPassProg->findUniformVariable("msFai1").set(r->getMs().getFai1());
  709. #endif
  710. lightPassProg->findUniformVariable("msDepthFai").set(
  711. r->getMs().getDepthFai());
  712. lightPassProg->findUniformVariable("shadowMapArr").set(sm.sm2DArrayTex);
  713. quadVao.bind();
  714. glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, TILES_COUNT);
  715. }
  716. //==============================================================================
  717. void Is::setState()
  718. {
  719. fbo.bind();
  720. r->clearAfterBindingFbo(
  721. GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  722. GlStateSingleton::get().setViewport(
  723. 0, 0, r->getWidth(), r->getHeight());
  724. GlStateSingleton::get().disable(GL_DEPTH_TEST);
  725. GlStateSingleton::get().disable(GL_BLEND);
  726. }
  727. //==============================================================================
  728. void Is::run()
  729. {
  730. SceneGraph& scene = r->getSceneGraph();
  731. cam = &scene.getActiveCamera();
  732. GlStateSingleton::get().disable(GL_BLEND);
  733. // Ground light direction
  734. Vec3 groundLightDir;
  735. if(groundLightEnabled)
  736. {
  737. groundLightDir = -cam->getViewMatrix().getColumn(1).xyz();
  738. }
  739. // Write common block
  740. if(commonUboUpdateTimestamp < r->getPlanesUpdateTimestamp()
  741. || commonUboUpdateTimestamp < scene.getAmbientColorUpdateTimestamp()
  742. || commonUboUpdateTimestamp == 1
  743. || (groundLightEnabled
  744. && !groundVectorsEqual(groundLightDir, prevGroundLightDir)))
  745. {
  746. shader::CommonUniforms blk;
  747. blk.planes = Vec4(r->getPlanes().x(), r->getPlanes().y(), 0.0, 0.0);
  748. blk.sceneAmbientColor = Vec4(scene.getAmbientColor(), 0.0);
  749. if(groundLightEnabled)
  750. {
  751. blk.groundLightDir = Vec4(groundLightDir, 1.0);
  752. prevGroundLightDir = groundLightDir;
  753. }
  754. commonUbo.write(&blk);
  755. commonUboUpdateTimestamp = getGlobTimestamp();
  756. }
  757. // Do the light pass including the shadow passes
  758. lightPass();
  759. }
  760. } // end namespace anki