Tiler.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #include "anki/renderer/Tiler.h"
  2. #include "anki/renderer/Renderer.h"
  3. #include "anki/resource/ShaderProgramResource.h"
  4. #include "anki/core/ThreadPool.h"
  5. #include "anki/scene/Camera.h"
  6. #include "anki/scene/Spatial.h"
  7. // Default should be 0
  8. #define ANKI_TILER_ENABLE_GPU 0
  9. namespace anki {
  10. //==============================================================================
  11. // Misc =
  12. //==============================================================================
  13. //==============================================================================
  14. #define CHECK_PLANE_PTR(p_) \
  15. ANKI_ASSERT(p_ < &tiler->allPlanes[tiler->allPlanes.size()]);
  16. /// Job that updates the left, right, top and buttom tile planes
  17. struct UpdatePlanesPerspectiveCameraJob: ThreadJob
  18. {
  19. Tiler* tiler = nullptr;
  20. PerspectiveCamera* cam = nullptr;
  21. Bool frustumChanged;
  22. #if ANKI_TILER_ENABLE_GPU
  23. const PixelArray* pixels = nullptr;
  24. #endif
  25. void operator()(U threadId, U threadsCount)
  26. {
  27. #if ANKI_TILER_ENABLE_GPU
  28. ANKI_ASSERT(tiler && cam && pixels);
  29. #endif
  30. U64 start, end;
  31. Transform trf = Transform(cam->getWorldTransform());
  32. if(frustumChanged)
  33. {
  34. // Re-calculate the planes in local space
  35. const F32 fx = cam->getFovX();
  36. const F32 fy = cam->getFovY();
  37. const F32 n = cam->getNear();
  38. // Calculate l6 and o6 used to rotate the planes
  39. F32 l = 2.0 * n * tan(fx / 2.0);
  40. F32 l6 = l / tiler->r->getTilesCount().x();
  41. F32 o = 2.0 * n * tan(fy / 2.0);
  42. F32 o6 = o / tiler->r->getTilesCount().y();
  43. // First the top looking planes
  44. choseStartEnd(
  45. threadId, threadsCount, tiler->r->getTilesCount().y() - 1,
  46. start, end);
  47. for(U i = start; i < end; i++)
  48. {
  49. calcPlaneI(i, o6);
  50. CHECK_PLANE_PTR(&tiler->planesYW[i]);
  51. CHECK_PLANE_PTR(&tiler->planesY[i]);
  52. tiler->planesYW[i] = tiler->planesY[i].getTransformed(trf);
  53. }
  54. // Then the right looking planes
  55. choseStartEnd(
  56. threadId, threadsCount, tiler->r->getTilesCount().x() - 1,
  57. start, end);
  58. for(U j = start; j < end; j++)
  59. {
  60. calcPlaneJ(j, l6);
  61. CHECK_PLANE_PTR(&tiler->planesXW[j]);
  62. CHECK_PLANE_PTR(&tiler->planesX[j]);
  63. tiler->planesXW[j] = tiler->planesX[j].getTransformed(trf);
  64. }
  65. }
  66. else
  67. {
  68. // Only transform planes
  69. // First the top looking planes
  70. choseStartEnd(
  71. threadId, threadsCount, tiler->r->getTilesCount().y() - 1,
  72. start, end);
  73. for(U i = start; i < end; i++)
  74. {
  75. CHECK_PLANE_PTR(&tiler->planesYW[i]);
  76. CHECK_PLANE_PTR(&tiler->planesY[i]);
  77. tiler->planesYW[i] = tiler->planesY[i].getTransformed(trf);
  78. }
  79. // Then the right looking planes
  80. choseStartEnd(
  81. threadId, threadsCount, tiler->r->getTilesCount().x() - 1,
  82. start, end);
  83. for(U j = start; j < end; j++)
  84. {
  85. CHECK_PLANE_PTR(&tiler->planesXW[j]);
  86. CHECK_PLANE_PTR(&tiler->planesX[j]);
  87. tiler->planesXW[j] = tiler->planesX[j].getTransformed(trf);
  88. }
  89. }
  90. // Update the near far planes
  91. #if ANKI_TILER_ENABLE_GPU
  92. Vec2 rplanes;
  93. Renderer::calcPlanes(Vec2(cam->getNear(), cam->getFar()), rplanes);
  94. choseStartEnd(
  95. threadId, threadsCount,
  96. tiler->r->getTilesCount().x() * tiler->r->getTilesCount().y(),
  97. start, end);
  98. Plane* nearPlanesW = tiler->nearPlanesW + start;
  99. Plane* farPlanesW = tiler->farPlanesW + start;
  100. for(U k = start; k < end; ++k)
  101. {
  102. U j = k % tiler->r->getTilesCount().x();
  103. U i = k / tiler->r->getTilesCount().x();
  104. // Calculate depth as you do it for the vertex position inside
  105. // the shaders
  106. F32 minZ = rplanes.y() / (rplanes.x() + (*pixels)[i][j][0]);
  107. F32 maxZ = rplanes.y() / (rplanes.x() + (*pixels)[i][j][1]);
  108. // Calc the planes
  109. Plane nearPlane = Plane(Vec3(0.0, 0.0, -1.0), minZ);
  110. Plane farPlane = Plane(Vec3(0.0, 0.0, 1.0), -maxZ);
  111. // Tranform them
  112. CHECK_PLANE_PTR(nearPlanesW);
  113. *nearPlanesW = nearPlane.getTransformed(trf);
  114. CHECK_PLANE_PTR(farPlanesW);
  115. *farPlanesW = farPlane.getTransformed(trf);
  116. // Advance
  117. ++nearPlanesW;
  118. ++farPlanesW;
  119. }
  120. #endif
  121. }
  122. /// Calculate and set a top looking plane
  123. void calcPlaneI(U i, const F32 o6)
  124. {
  125. Vec3 a, b;
  126. const F32 n = cam->getNear();
  127. Plane& plane = tiler->planesY[i];
  128. CHECK_PLANE_PTR(&plane);
  129. a = Vec3(0.0,
  130. (I(i + 1) - I(tiler->r->getTilesCount().y()) / 2) * o6,
  131. -n);
  132. b = Vec3(1.0, 0.0, 0.0).cross(a);
  133. b.normalize();
  134. plane = Plane(b, 0.0);
  135. }
  136. /// Calculate and set a right looking plane
  137. void calcPlaneJ(U j, const F32 l6)
  138. {
  139. Vec3 a, b;
  140. const F32 n = cam->getNear();
  141. Plane& plane = tiler->planesX[j];
  142. CHECK_PLANE_PTR(&plane);
  143. a = Vec3((I(j + 1) - I(tiler->r->getTilesCount().x()) / 2) * l6,
  144. 0.0,
  145. -n);
  146. b = a.cross(Vec3(0.0, 1.0, 0.0));
  147. b.normalize();
  148. plane = Plane(b, 0.0);
  149. }
  150. };
  151. #undef CHECK_PLANE_PTR
  152. //==============================================================================
  153. // Tiler =
  154. //==============================================================================
  155. //==============================================================================
  156. Tiler::Tiler()
  157. {}
  158. //==============================================================================
  159. Tiler::~Tiler()
  160. {}
  161. //==============================================================================
  162. void Tiler::init(Renderer* r_)
  163. {
  164. try
  165. {
  166. initInternal(r_);
  167. }
  168. catch(const std::exception& e)
  169. {
  170. throw ANKI_EXCEPTION("Failed to init tiler") << e;
  171. }
  172. }
  173. //==============================================================================
  174. void Tiler::initInternal(Renderer* r_)
  175. {
  176. r = r_;
  177. // Load the program
  178. std::stringstream pps;
  179. pps << "#define TILES_X_COUNT " << r->getTilesCount().x() << "\n"
  180. << "#define TILES_Y_COUNT " << r->getTilesCount().y() << "\n"
  181. << "#define RENDERER_WIDTH " << r->getWidth() << "\n"
  182. << "#define RENDERER_HEIGHT " << r->getHeight() << "\n";
  183. prog.load(ShaderProgramResource::createSrcCodeToCache(
  184. "shaders/TilerMinMax.glsl", pps.str().c_str(), "r_").c_str());
  185. depthMapUniform = &(prog->findUniformVariable("depthMap"));
  186. // Create FBO
  187. fai.create2dFai(r->getTilesCount().x(), r->getTilesCount().y(),
  188. GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);
  189. fai.setFiltering(Texture::TFT_NEAREST);
  190. fbo.create();
  191. fbo.setColorAttachments({&fai});
  192. if(!fbo.isComplete())
  193. {
  194. throw ANKI_EXCEPTION("FBO not complete");
  195. }
  196. // Create PBO
  197. pbo.create(GL_PIXEL_PACK_BUFFER,
  198. r->getTilesCount().x() * r->getTilesCount().y() * 2 * sizeof(F32),
  199. nullptr);
  200. // Init planes
  201. U planesCount =
  202. (r->getTilesCount().x() - 1) * 2 // planes J
  203. + (r->getTilesCount().y() - 1) * 2 // planes I
  204. + (r->getTilesCount().x() * r->getTilesCount().y() * 2);
  205. // near far planes
  206. allPlanes.resize(planesCount);
  207. planesX = &allPlanes[0];
  208. planesY = planesX + r->getTilesCount().x() - 1;
  209. planesXW = planesY + r->getTilesCount().y() - 1;
  210. planesYW = planesXW + r->getTilesCount().x() - 1;
  211. nearPlanesW = planesYW + r->getTilesCount().y() - 1;
  212. farPlanesW = nearPlanesW + r->getTilesCount().x() * r->getTilesCount().y();
  213. }
  214. //==============================================================================
  215. void Tiler::runMinMax(const Texture& depthMap)
  216. {
  217. #if ANKI_TILER_ENABLE_GPU
  218. ANKI_ASSERT(depthMap.getFiltering() == Texture::TFT_NEAREST);
  219. // Issue the min/max job
  220. fbo.bind();
  221. GlStateSingleton::get().setViewport(
  222. 0, 0, r->getTilesCount().x(), r->getTilesCount().y());
  223. r->clearAfterBindingFbo(GL_COLOR_BUFFER_BIT);
  224. prog->bind();
  225. ANKI_ASSERT(depthMapUniform);
  226. depthMapUniform->set(depthMap);
  227. r->drawQuad();
  228. // Issue the async pixel read
  229. pbo.bind();
  230. glReadPixels(0, 0, r->getTilesCount().x(), r->getTilesCount().y(),
  231. GL_RG_INTEGER, GL_UNSIGNED_INT, nullptr);
  232. pbo.unbind();
  233. #endif
  234. }
  235. //==============================================================================
  236. void Tiler::updateTiles(Camera& cam)
  237. {
  238. //
  239. // Read the results from the minmax job. It will block
  240. //
  241. #if ANKI_TILER_ENABLE_GPU
  242. PixelArray pixels;
  243. pbo.read(&pixels[0][0]);
  244. #endif
  245. //
  246. // Issue parallel jobs
  247. //
  248. Array<UpdatePlanesPerspectiveCameraJob, ThreadPool::MAX_THREADS> jobs;
  249. U32 camTimestamp = cam.getFrustumable()->getFrustumableTimestamp();
  250. // Do a job that transforms only the planes when:
  251. // - it is the same camera as before and
  252. // - the camera frustum have not changed
  253. Bool frustumChanged =
  254. camTimestamp >= planes4UpdateTimestamp || prevCam != &cam;
  255. ThreadPool& threadPool = ThreadPoolSingleton::get();
  256. switch(cam.getCameraType())
  257. {
  258. case Camera::CT_PERSPECTIVE:
  259. for(U i = 0; i < threadPool.getThreadsCount(); i++)
  260. {
  261. jobs[i].tiler = this;
  262. jobs[i].cam = static_cast<PerspectiveCamera*>(&cam);
  263. #if ANKI_TILER_ENABLE_GPU
  264. jobs[i].pixels = &pixels;
  265. #endif
  266. jobs[i].frustumChanged = frustumChanged;
  267. threadPool.assignNewJob(i, &jobs[i]);
  268. }
  269. break;
  270. default:
  271. ANKI_ASSERT(0 && "Unimplemented");
  272. break;
  273. }
  274. // Update timestamp
  275. if(frustumChanged)
  276. {
  277. planes4UpdateTimestamp = getGlobTimestamp();
  278. }
  279. // Sync threads
  280. threadPool.waitForAllJobsToFinish();
  281. //
  282. // Misc
  283. //
  284. prevCam = &cam;
  285. }
  286. //==============================================================================
  287. Bool Tiler::test(
  288. const CollisionShape& cs,
  289. Bool nearPlane,
  290. Bitset* outBitset) const
  291. {
  292. Bitset bitset;
  293. /// Call the recursive function
  294. testRange(cs, nearPlane, 0, r->getTilesCount().y(), 0,
  295. r->getTilesCount().x(), bitset);
  296. if(outBitset)
  297. {
  298. *outBitset = bitset;
  299. }
  300. return bitset.any();
  301. }
  302. //==============================================================================
  303. void Tiler::testRange(const CollisionShape& cs, Bool nearPlane,
  304. U yFrom, U yTo, U xFrom, U xTo, Bitset& bitset) const
  305. {
  306. U mi = (yTo - yFrom) / 2;
  307. U mj = (xTo - xFrom) / 2;
  308. ANKI_ASSERT(mi == mj && "Change the algorithm if they are not the same");
  309. // Handle final
  310. if(mi == 0 || mj == 0)
  311. {
  312. U tileId = yFrom * r->getTilesCount().x() + xFrom;
  313. Bool inside = true;
  314. #if ANKI_TILER_ENABLE_GPU
  315. if(cs.testPlane(farPlanesW[tileId]) >= 0.0)
  316. {
  317. // Inside on far but check near
  318. if(nearPlane)
  319. {
  320. if(cs.testPlane(nearPlanesW[tileId]) >= 0)
  321. {
  322. // Inside
  323. }
  324. else
  325. {
  326. inside = false;
  327. }
  328. }
  329. else
  330. {
  331. // Inside
  332. }
  333. }
  334. else
  335. {
  336. inside = false;
  337. }
  338. #endif
  339. bitset.set(tileId, inside);
  340. return;
  341. }
  342. // Pick the correct top lookin plane (y)
  343. const Plane& topPlane = planesYW[yFrom + mi - 1];
  344. // Pick the correct right looking plane (x)
  345. const Plane& rightPlane = planesXW[xFrom + mj - 1];
  346. // Do the checks
  347. Bool inside[2][2] = {{false, false}, {false, false}};
  348. F32 test;
  349. // Top looking plane check
  350. test = cs.testPlane(topPlane);
  351. if(test < 0.0)
  352. {
  353. inside[0][0] = inside[0][1] = true;
  354. }
  355. else if(test > 0.0)
  356. {
  357. inside[1][0] = inside[1][1] = true;
  358. }
  359. else
  360. {
  361. // Possibly all inside
  362. for(U i = 0; i < 2; i++)
  363. {
  364. for(U j = 0; j < 2; j++)
  365. {
  366. inside[i][j] = true;
  367. }
  368. }
  369. }
  370. // Right looking plane check
  371. test = cs.testPlane(rightPlane);
  372. if(test < 0.0)
  373. {
  374. inside[0][1] = inside[1][1] = false;
  375. }
  376. else if(test > 0.0)
  377. {
  378. inside[0][0] = inside[1][0] = false;
  379. }
  380. else
  381. {
  382. // Do nothing and keep the top looking plane check results
  383. }
  384. // Now move lower to the hierarchy
  385. for(U i = 0; i < 2; i++)
  386. {
  387. for(U j = 0; j < 2; j++)
  388. {
  389. if(inside[i][j])
  390. {
  391. testRange(cs, nearPlane,
  392. yFrom + (i * mi), yFrom + ((i + 1) * mi),
  393. xFrom + (j * mj), xFrom + ((j + 1) * mj),
  394. bitset);
  395. }
  396. }
  397. }
  398. }
  399. } // end namespace anki