bvh_builder_morton.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // ======================================================================== //
  2. // Copyright 2009-2017 Intel Corporation //
  3. // //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); //
  5. // you may not use this file except in compliance with the License. //
  6. // You may obtain a copy of the License at //
  7. // //
  8. // http://www.apache.org/licenses/LICENSE-2.0 //
  9. // //
  10. // Unless required by applicable law or agreed to in writing, software //
  11. // distributed under the License is distributed on an "AS IS" BASIS, //
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
  13. // See the License for the specific language governing permissions and //
  14. // limitations under the License. //
  15. // ======================================================================== //
  16. #include "bvh.h"
  17. #include "bvh_statistics.h"
  18. #include "bvh_rotate.h"
  19. #include "../common/profile.h"
  20. #include "../../common/algorithms/parallel_prefix_sum.h"
  21. #include "../builders/primrefgen.h"
  22. #include "../builders/bvh_builder_morton.h"
  23. #include "../geometry/triangle.h"
  24. #include "../geometry/trianglev.h"
  25. #include "../geometry/trianglei.h"
  26. #include "../geometry/quadv.h"
  27. #include "../geometry/quadi.h"
  28. #include "../geometry/object.h"
  29. #define ROTATE_TREE 1 // specifies number of tree rotation rounds to perform
  30. namespace embree
  31. {
  32. namespace isa
  33. {
  34. template<int N>
  35. struct SetBVHNBounds
  36. {
  37. typedef BVHN<N> BVH;
  38. typedef typename BVH::NodeRef NodeRef;
  39. typedef typename BVH::AlignedNode AlignedNode;
  40. BVH* bvh;
  41. __forceinline SetBVHNBounds (BVH* bvh) : bvh(bvh) {}
  42. __forceinline std::pair<NodeRef,BBox3fa> operator() (NodeRef ref, const std::pair<NodeRef,BBox3fa>* children, size_t num)
  43. {
  44. AlignedNode* node = ref.alignedNode();
  45. BBox3fa res = empty;
  46. for (size_t i=0; i<num; i++) {
  47. const BBox3fa b = children[i].second;
  48. res.extend(b);
  49. node->set(i,children[i].first);
  50. node->set(i,b);
  51. }
  52. #if ROTATE_TREE
  53. if (N == 4)
  54. {
  55. size_t n = 0;
  56. for (size_t i=0; i<num; i++)
  57. n += children[i].second.lower.a;
  58. if (n >= 4096) {
  59. for (size_t i=0; i<num; i++) {
  60. if (children[i].second.lower.a < 4096) {
  61. for (int j=0; j<ROTATE_TREE; j++)
  62. BVHNRotate<N>::rotate(node->child(i));
  63. node->child(i).setBarrier();
  64. }
  65. }
  66. }
  67. res.lower.a = unsigned(n);
  68. }
  69. #endif
  70. return std::make_pair(ref,res);
  71. }
  72. };
  73. template<int N, typename Primitive>
  74. struct CreateMortonLeaf;
  75. template<int N>
  76. struct CreateMortonLeaf<N,Triangle4>
  77. {
  78. typedef BVHN<N> BVH;
  79. typedef typename BVH::NodeRef NodeRef;
  80. __forceinline CreateMortonLeaf (TriangleMesh* mesh, BVHBuilderMorton::BuildPrim* morton)
  81. : mesh(mesh), morton(morton) {}
  82. __noinline std::pair<NodeRef,BBox3fa> operator() (const range<unsigned>& current, FastAllocator::ThreadLocal2* alloc)
  83. {
  84. vfloat4 lower(pos_inf);
  85. vfloat4 upper(neg_inf);
  86. size_t items = current.size();
  87. size_t start = current.begin();
  88. assert(items<=4);
  89. /* allocate leaf node */
  90. Triangle4* accel = (Triangle4*) alloc->alloc1->malloc(sizeof(Triangle4),BVH::byteAlignment);
  91. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  92. vint4 vgeomID = -1, vprimID = -1;
  93. Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
  94. const unsigned geomID = this->mesh->id;
  95. const TriangleMesh* __restrict__ const mesh = this->mesh;
  96. for (size_t i=0; i<items; i++)
  97. {
  98. const unsigned primID = morton[start+i].index;
  99. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  100. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  101. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  102. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  103. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  104. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  105. vgeomID [i] = geomID;
  106. vprimID [i] = primID;
  107. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  108. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  109. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  110. }
  111. Triangle4::store_nt(accel,Triangle4(v0,v1,v2,vgeomID,vprimID));
  112. BBox3fa box_o = BBox3fa((Vec3fa)lower,(Vec3fa)upper);
  113. #if ROTATE_TREE
  114. if (N == 4)
  115. box_o.lower.a = unsigned(current.size());
  116. #endif
  117. return std::make_pair(ref,box_o);
  118. }
  119. private:
  120. TriangleMesh* mesh;
  121. BVHBuilderMorton::BuildPrim* morton;
  122. };
  123. template<int N>
  124. struct CreateMortonLeaf<N,Triangle4v>
  125. {
  126. typedef BVHN<N> BVH;
  127. typedef typename BVH::NodeRef NodeRef;
  128. __forceinline CreateMortonLeaf (TriangleMesh* mesh, BVHBuilderMorton::BuildPrim* morton)
  129. : mesh(mesh), morton(morton) {}
  130. __noinline std::pair<NodeRef,BBox3fa> operator() (const range<unsigned>& current, FastAllocator::ThreadLocal2* alloc)
  131. {
  132. vfloat4 lower(pos_inf);
  133. vfloat4 upper(neg_inf);
  134. size_t items = current.size();
  135. size_t start = current.begin();
  136. assert(items<=4);
  137. /* allocate leaf node */
  138. Triangle4v* accel = (Triangle4v*) alloc->alloc1->malloc(sizeof(Triangle4v),BVH::byteAlignment);
  139. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  140. vint4 vgeomID = -1, vprimID = -1;
  141. Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
  142. const unsigned geomID = this->mesh->id;
  143. const TriangleMesh* __restrict__ mesh = this->mesh;
  144. for (size_t i=0; i<items; i++)
  145. {
  146. const unsigned primID = morton[start+i].index;
  147. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  148. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  149. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  150. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  151. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  152. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  153. vgeomID [i] = geomID;
  154. vprimID [i] = primID;
  155. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  156. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  157. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  158. }
  159. Triangle4v::store_nt(accel,Triangle4v(v0,v1,v2,vgeomID,vprimID));
  160. BBox3fa box_o = BBox3fa((Vec3fa)lower,(Vec3fa)upper);
  161. #if ROTATE_TREE
  162. if (N == 4)
  163. box_o.lower.a = current.size();
  164. #endif
  165. return std::make_pair(ref,box_o);
  166. }
  167. private:
  168. TriangleMesh* mesh;
  169. BVHBuilderMorton::BuildPrim* morton;
  170. };
  171. template<int N>
  172. struct CreateMortonLeaf<N,Triangle4i>
  173. {
  174. typedef BVHN<N> BVH;
  175. typedef typename BVH::NodeRef NodeRef;
  176. __forceinline CreateMortonLeaf (TriangleMesh* mesh, BVHBuilderMorton::BuildPrim* morton)
  177. : mesh(mesh), morton(morton) {}
  178. __noinline std::pair<NodeRef,BBox3fa> operator() (const range<unsigned>& current, FastAllocator::ThreadLocal2* alloc)
  179. {
  180. vfloat4 lower(pos_inf);
  181. vfloat4 upper(neg_inf);
  182. size_t items = current.size();
  183. size_t start = current.begin();
  184. assert(items<=4);
  185. /* allocate leaf node */
  186. Triangle4i* accel = (Triangle4i*) alloc->alloc1->malloc(sizeof(Triangle4i),BVH::byteAlignment);
  187. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  188. vint4 vgeomID = -1, vprimID = -1;
  189. vint4 v0 = zero, v1 = zero, v2 = zero;
  190. const unsigned geomID = this->mesh->id;
  191. const TriangleMesh* __restrict__ const mesh = this->mesh;
  192. for (size_t i=0; i<items; i++)
  193. {
  194. const unsigned primID = morton[start+i].index;
  195. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  196. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  197. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  198. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  199. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  200. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  201. vgeomID[i] = geomID;
  202. vprimID[i] = primID;
  203. int* base = (int*) mesh->vertexPtr(tri.v[0]);
  204. v0[i] = tri.v[0];
  205. v1[i] = int(ssize_t((int*)mesh->vertexPtr(tri.v[1])-base));
  206. v2[i] = int(ssize_t((int*)mesh->vertexPtr(tri.v[2])-base));
  207. }
  208. for (size_t i=items; i<4; i++)
  209. {
  210. vgeomID[i] = vgeomID[0];
  211. vprimID[i] = -1;
  212. v0[i] = 0;
  213. v1[i] = 0;
  214. v2[i] = 0;
  215. }
  216. Triangle4i::store_nt(accel,Triangle4i(v0,v1,v2,vgeomID,vprimID));
  217. BBox3fa box_o = BBox3fa((Vec3fa)lower,(Vec3fa)upper);
  218. #if ROTATE_TREE
  219. if (N == 4)
  220. box_o.lower.a = current.size();
  221. #endif
  222. return std::make_pair(ref,box_o);
  223. }
  224. private:
  225. TriangleMesh* mesh;
  226. BVHBuilderMorton::BuildPrim* morton;
  227. };
  228. template<int N>
  229. struct CreateMortonLeaf<N,Quad4v>
  230. {
  231. typedef BVHN<N> BVH;
  232. typedef typename BVH::NodeRef NodeRef;
  233. __forceinline CreateMortonLeaf (QuadMesh* mesh, BVHBuilderMorton::BuildPrim* morton)
  234. : mesh(mesh), morton(morton) {}
  235. __noinline std::pair<NodeRef,BBox3fa> operator() (const range<unsigned>& current, FastAllocator::ThreadLocal2* alloc)
  236. {
  237. vfloat4 lower(pos_inf);
  238. vfloat4 upper(neg_inf);
  239. size_t items = current.size();
  240. size_t start = current.begin();
  241. assert(items<=4);
  242. /* allocate leaf node */
  243. Quad4v* accel = (Quad4v*) alloc->alloc1->malloc(sizeof(Quad4v),BVH::byteAlignment);
  244. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  245. vint4 vgeomID = -1, vprimID = -1;
  246. Vec3vf4 v0 = zero, v1 = zero, v2 = zero, v3 = zero;
  247. const unsigned geomID = this->mesh->id;
  248. const QuadMesh* __restrict__ mesh = this->mesh;
  249. for (size_t i=0; i<items; i++)
  250. {
  251. const unsigned primID = morton[start+i].index;
  252. const QuadMesh::Quad& tri = mesh->quad(primID);
  253. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  254. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  255. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  256. const Vec3fa& p3 = mesh->vertex(tri.v[3]);
  257. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
  258. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
  259. vgeomID [i] = geomID;
  260. vprimID [i] = primID;
  261. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  262. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  263. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  264. v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
  265. }
  266. Quad4v::store_nt(accel,Quad4v(v0,v1,v2,v3,vgeomID,vprimID));
  267. BBox3fa box_o = BBox3fa((Vec3fa)lower,(Vec3fa)upper);
  268. #if ROTATE_TREE
  269. if (N == 4)
  270. box_o.lower.a = current.size();
  271. #endif
  272. return std::make_pair(ref,box_o);
  273. }
  274. private:
  275. QuadMesh* mesh;
  276. BVHBuilderMorton::BuildPrim* morton;
  277. };
  278. template<int N>
  279. struct CreateMortonLeaf<N,Object>
  280. {
  281. typedef BVHN<N> BVH;
  282. typedef typename BVH::NodeRef NodeRef;
  283. __forceinline CreateMortonLeaf (AccelSet* mesh, BVHBuilderMorton::BuildPrim* morton)
  284. : mesh(mesh), morton(morton) {}
  285. __noinline std::pair<NodeRef,BBox3fa> operator() (const range<unsigned>& current, FastAllocator::ThreadLocal2* alloc)
  286. {
  287. vfloat4 lower(pos_inf);
  288. vfloat4 upper(neg_inf);
  289. size_t items = current.size();
  290. size_t start = current.begin();
  291. /* allocate leaf node */
  292. Object* accel = (Object*) alloc->alloc1->malloc(items*sizeof(Object),BVH::byteAlignment);
  293. NodeRef ref = BVH::encodeLeaf((char*)accel,items);
  294. const unsigned geomID = this->mesh->id;
  295. const AccelSet* mesh = this->mesh;
  296. BBox3fa bounds = empty;
  297. for (size_t i=0; i<items; i++)
  298. {
  299. const unsigned index = morton[start+i].index;
  300. const unsigned primID = index;
  301. bounds.extend(mesh->bounds(primID));
  302. new (&accel[i]) Object(geomID,primID);
  303. }
  304. BBox3fa box_o = bounds;
  305. #if ROTATE_TREE
  306. if (N == 4)
  307. box_o.lower.a = current.size();
  308. #endif
  309. return std::make_pair(ref,box_o);
  310. }
  311. private:
  312. AccelSet* mesh;
  313. BVHBuilderMorton::BuildPrim* morton;
  314. };
  315. template<typename Mesh>
  316. struct CalculateMeshBounds
  317. {
  318. __forceinline CalculateMeshBounds (Mesh* mesh)
  319. : mesh(mesh) {}
  320. __forceinline const BBox3fa operator() (const BVHBuilderMorton::BuildPrim& morton) {
  321. return mesh->bounds(morton.index);
  322. }
  323. private:
  324. Mesh* mesh;
  325. };
  326. template<int N, typename Mesh, typename Primitive>
  327. class BVHNMeshBuilderMorton : public Builder
  328. {
  329. typedef BVHN<N> BVH;
  330. typedef typename BVH::AlignedNode AlignedNode;
  331. typedef typename BVH::NodeRef NodeRef;
  332. public:
  333. BVHNMeshBuilderMorton (BVH* bvh, Mesh* mesh, const size_t minLeafSize, const size_t maxLeafSize, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD)
  334. : bvh(bvh), mesh(mesh), morton(bvh->device), settings(N,BVH::maxBuildDepth,minLeafSize,maxLeafSize,singleThreadThreshold) {}
  335. /* build function */
  336. void build()
  337. {
  338. /* we reset the allocator when the mesh size changed */
  339. if (mesh->numPrimitivesChanged) {
  340. bvh->alloc.clear();
  341. morton.clear();
  342. mesh->numPrimitivesChanged = false;
  343. }
  344. size_t numPrimitives = mesh->size();
  345. /* skip build for empty scene */
  346. if (numPrimitives == 0) {
  347. bvh->set(BVH::emptyNode,empty,0);
  348. return;
  349. }
  350. /* preallocate arrays */
  351. morton.resize(numPrimitives);
  352. size_t bytesAllocated = numPrimitives*sizeof(AlignedNode)/(4*N) + size_t(1.2f*Primitive::blocks(numPrimitives)*sizeof(Primitive));
  353. size_t bytesMortonCodes = numPrimitives*sizeof(BVHBuilderMorton::BuildPrim);
  354. bytesAllocated = max(bytesAllocated,bytesMortonCodes); // the first allocation block is reused to sort the morton codes
  355. bvh->alloc.init(bytesAllocated,2*bytesAllocated);
  356. /* create morton code array */
  357. BVHBuilderMorton::BuildPrim* dest = (BVHBuilderMorton::BuildPrim*) bvh->alloc.specialAlloc(bytesMortonCodes);
  358. size_t numPrimitivesGen = createMortonCodeArray<Mesh>(mesh,morton,bvh->scene->progressInterface);
  359. /* create BVH */
  360. SetBVHNBounds<N> setBounds(bvh);
  361. CreateMortonLeaf<N,Primitive> createLeaf(mesh,morton.data());
  362. CalculateMeshBounds<Mesh> calculateBounds(mesh);
  363. auto root = BVHBuilderMorton::build<std::pair<NodeRef,BBox3fa>>(
  364. typename BVH::CreateAlloc(bvh),
  365. typename BVH::AlignedNode::Create(),
  366. setBounds,createLeaf,calculateBounds,bvh->scene->progressInterface,
  367. morton.data(),dest,numPrimitivesGen,settings);
  368. bvh->set(root.first,LBBox3fa(root.second),numPrimitives);
  369. #if ROTATE_TREE
  370. if (N == 4)
  371. {
  372. for (int i=0; i<ROTATE_TREE; i++)
  373. BVHNRotate<N>::rotate(bvh->root);
  374. bvh->clearBarrier(bvh->root);
  375. }
  376. #endif
  377. /* clear temporary data for static geometry */
  378. if (mesh->isStatic())
  379. {
  380. morton.clear();
  381. bvh->shrink();
  382. }
  383. bvh->cleanup();
  384. }
  385. void clear() {
  386. morton.clear();
  387. }
  388. private:
  389. BVH* bvh;
  390. Mesh* mesh;
  391. mvector<BVHBuilderMorton::BuildPrim> morton;
  392. BVHBuilderMorton::Settings settings;
  393. };
  394. #if defined(EMBREE_GEOMETRY_TRIANGLES)
  395. Builder* BVH4Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4> ((BVH4*)bvh,mesh,4,4); }
  396. Builder* BVH4Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4v>((BVH4*)bvh,mesh,4,4); }
  397. Builder* BVH4Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4i>((BVH4*)bvh,mesh,4,4); }
  398. #if defined(__AVX__)
  399. Builder* BVH8Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4> ((BVH8*)bvh,mesh,4,4); }
  400. Builder* BVH8Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4v>((BVH8*)bvh,mesh,4,4); }
  401. Builder* BVH8Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4i>((BVH8*)bvh,mesh,4,4); }
  402. #endif
  403. #endif
  404. #if defined(EMBREE_GEOMETRY_QUADS)
  405. Builder* BVH4Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<4,QuadMesh,Quad4v>((BVH4*)bvh,mesh,4,4); }
  406. #if defined(__AVX__)
  407. Builder* BVH8Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<8,QuadMesh,Quad4v>((BVH8*)bvh,mesh,4,4); }
  408. #endif
  409. #endif
  410. #if defined(EMBREE_GEOMETRY_USER)
  411. Builder* BVH4VirtualMeshBuilderMortonGeneral (void* bvh, AccelSet* mesh, size_t mode) { return new class BVHNMeshBuilderMorton<4,AccelSet,Object>((BVH4*)bvh,mesh,1,BVH4::maxLeafBlocks); }
  412. #endif
  413. }
  414. }