bvh_builder_instancing.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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_builder_instancing.h"
  17. #include "bvh_statistics.h"
  18. #include "../builders/bvh_builder_sah.h"
  19. #include "../geometry/triangle.h"
  20. #include "../geometry/trianglev_mb.h"
  21. #include "../geometry/quadv.h"
  22. #include "../geometry/quadi.h"
  23. #include "../geometry/quadi_mb.h"
  24. namespace embree
  25. {
  26. namespace isa
  27. {
  28. template<int N, typename Mesh>
  29. BVHNBuilderInstancing<N,Mesh>::BVHNBuilderInstancing (BVH* bvh, Scene* scene, const createMeshAccelTy createMeshAccel)
  30. : bvh(bvh), objects(bvh->objects), createMeshAccel(createMeshAccel), scene(scene), refs(scene->device), prims(scene->device), nextRef(0) {}
  31. template<int N, typename Mesh>
  32. BVHNBuilderInstancing<N,Mesh>::~BVHNBuilderInstancing ()
  33. {
  34. for (size_t i=0; i<builders.size(); i++)
  35. delete builders[i];
  36. }
  37. int hash(const Vec3fa& vec)
  38. {
  39. int h = 0;
  40. for (size_t i=0; i<3; i++)
  41. h ^= 0x42F276E1*i*((int*)&vec)[i];
  42. return h;
  43. }
  44. int hash(const AffineSpace3fa& space)
  45. {
  46. int h = 0;
  47. h ^= 0xF2FF7631*hash(space.l.vx);
  48. h ^= 0xF2FF7731*hash(space.l.vy);
  49. h ^= 0xF2FF7831*hash(space.l.vz);
  50. h ^= 0xF2FF7931*hash(space.p);
  51. return h;
  52. }
  53. /*int slot(int type, int numTimeSteps)
  54. {
  55. if (numTimeSteps == 1)
  56. {
  57. switch (type) {
  58. case Geometry::TRIANGLE_MESH: return 0;
  59. case Geometry::USER_GEOMETRY: break;
  60. case Geometry::BEZIER_CURVES: break;
  61. case Geometry::SUBDIV_MESH : break;
  62. }
  63. } else {
  64. switch (type) {
  65. case Geometry::TRIANGLE_MESH: return 1;
  66. case Geometry::USER_GEOMETRY: break;
  67. case Geometry::BEZIER_CURVES: break;
  68. case Geometry::SUBDIV_MESH : break;
  69. }
  70. }
  71. assert(false);
  72. return 0;
  73. }*/
  74. template<int N, typename Mesh>
  75. const BBox3fa xfmDeepBounds(const AffineSpace3fa& xfm, const BBox3fa& bounds, typename BVHN<N>::NodeRef ref, size_t depth)
  76. {
  77. if (ref == BVHN<N>::emptyNode) return empty;
  78. if (depth == 0 || !ref.isAlignedNode()) return xfmBounds(xfm,bounds);
  79. typename BVHN<N>::AlignedNode* node = ref.alignedNode();
  80. BBox3fa box = empty;
  81. for (size_t i=0; i<N; i++)
  82. box.extend(xfmDeepBounds<N>(xfm,node->bounds(i),node->child(i),depth-1));
  83. return box;
  84. }
  85. template<int N, typename Mesh>
  86. void BVHNBuilderInstancing<N,Mesh>::build()
  87. {
  88. /* delete some objects */
  89. size_t num = scene->size();
  90. if (num < objects.size()) {
  91. parallel_for(num, objects.size(), [&] (const range<size_t>& r) {
  92. for (size_t i=r.begin(); i<r.end(); i++) {
  93. delete builders[i]; builders[i] = nullptr;
  94. delete objects[i]; objects[i] = nullptr;
  95. }
  96. });
  97. }
  98. /* reset memory allocator */
  99. bvh->alloc.reset();
  100. /* skip build for empty scene */
  101. size_t numPrimitives = 0;
  102. //numPrimitives += scene->getNumPrimitives<TriangleMesh,false>();
  103. numPrimitives += scene->instanced.numTriangles;
  104. numPrimitives += scene->instancedMB.numTriangles;
  105. if (numPrimitives == 0) {
  106. prims.resize(0);
  107. bvh->set(BVH::emptyNode,empty,0);
  108. return;
  109. }
  110. double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderInstancing");
  111. /* resize object array if scene got larger */
  112. if (objects.size() < num) objects.resize(num);
  113. if (builders.size() < num) builders.resize(num);
  114. if (refs.size() < num) refs.resize(num);
  115. nextRef.store(0);
  116. /* creation of acceleration structures */
  117. parallel_for(size_t(0), num, [&] (const range<size_t>& r) {
  118. for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
  119. {
  120. Mesh* mesh = scene->getSafe<Mesh>(objectID);
  121. /* verify if geometry got deleted properly */
  122. if (mesh == nullptr) {
  123. assert(objectID < objects.size () && objects[objectID] == nullptr);
  124. assert(objectID < builders.size() && builders[objectID] == nullptr);
  125. continue;
  126. }
  127. /* create BVH and builder for new meshes */
  128. if (objects[objectID] == nullptr)
  129. createMeshAccel(mesh,(AccelData*&)objects[objectID],builders[objectID]);
  130. }
  131. });
  132. /* parallel build of acceleration structures */
  133. parallel_for(size_t(0), num, [&] (const range<size_t>& r) {
  134. for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
  135. {
  136. Geometry* geom = scene->get(objectID);
  137. if (geom == nullptr) continue;
  138. Builder* builder = builders[objectID];
  139. if (builder == nullptr) continue;
  140. if (geom->isModified() && geom->isInstanced())
  141. builder->build();
  142. }
  143. });
  144. /* creates all instances */
  145. parallel_for(size_t(0), num, [&] (const range<size_t>& r) {
  146. for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
  147. {
  148. Geometry* geom = scene->get(objectID);
  149. if (geom == nullptr) continue;
  150. if (!(geom->getType() & Geometry::INSTANCE)) continue;
  151. GeometryInstance* instance = (GeometryInstance*) geom;
  152. if (!instance->isEnabled()) continue;
  153. BVH* object = objects[instance->geom->id];
  154. if (object == nullptr) continue;
  155. if (object->getBounds().empty()) continue;
  156. int s = 0; //slot(geom->getType() & ~Geometry::INSTANCE, geom->numTimeSteps);
  157. refs[nextRef++] = BVHNBuilderInstancing::BuildRef(instance->local2world,object->getBounds(),object->root,instance->mask,unsigned(objectID),hash(instance->local2world),s);
  158. }
  159. });
  160. refs.resize(nextRef);
  161. #if 0
  162. /* compute transform IDs */
  163. std::sort(refs.begin(),refs.end(), [] (const BuildRef& ref0, const BuildRef& ref1) { return ref0.xfmID < ref1.xfmID; });
  164. int lastXfmID = 0;
  165. AffineSpace3fa lastXfm = one;
  166. for (size_t i=0; i<refs.size(); i++) {
  167. if (refs[i].local2world != lastXfm) {
  168. lastXfmID++;
  169. lastXfm = refs[i].local2world;
  170. }
  171. refs[i].xfmID = lastXfmID;
  172. }
  173. #endif
  174. /* fast path for single geometry scenes */
  175. /*if (nextRef == 1) {
  176. bvh->set(refs[0].node,refs[0].bounds(),numPrimitives);
  177. return;
  178. }*/
  179. /* open all large nodes */
  180. open(numPrimitives);
  181. /* fast path for small geometries */
  182. /*if (refs.size() == 1) {
  183. bvh->set(refs[0].node,refs[0].bounds(),numPrimitives);
  184. return;
  185. }*/
  186. bvh->alloc.init_estimate(refs.size()*16);
  187. /* compute PrimRefs */
  188. prims.resize(refs.size());
  189. const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), size_t(1024), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {
  190. PrimInfo pinfo(empty);
  191. for (size_t i=r.begin(); i<r.end(); i++)
  192. {
  193. const BBox3fa bounds = refs[i].worldBounds();
  194. pinfo.add(bounds);
  195. prims[i] = PrimRef(bounds,(size_t)&refs[i]);
  196. }
  197. return pinfo;
  198. }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
  199. /* skip if all objects where empty */
  200. if (pinfo.size() == 0)
  201. bvh->set(BVH::emptyNode,empty,0);
  202. #if 0 // this codepath is buggy, have to create transform node here too
  203. else if (pinfo.size() == 1) {
  204. BuildRef* ref = (BuildRef*) prims[0].ID();
  205. //const BBox3fa bounds = xfmBounds(ref->local2world,ref->localBounds);
  206. const BBox3fa bounds = xfmDeepBounds<N>(ref->local2world,ref->localBounds,ref->node,2);
  207. bvh->set(ref->node,LBBox3fa(bounds),numPrimitives);
  208. }
  209. #endif
  210. /* otherwise build toplevel hierarchy */
  211. else
  212. {
  213. /* settings for BVH build */
  214. GeneralBVHBuilder::Settings settings;
  215. settings.branchingFactor = N;
  216. settings.maxDepth = BVH::maxBuildDepthLeaf;
  217. settings.logBlockSize = __bsr(4);
  218. settings.minLeafSize = 1;
  219. settings.maxLeafSize = 1;
  220. settings.travCost = 1.0f;
  221. settings.intCost = 1.0f;
  222. settings.singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD;
  223. NodeRef root = BVHBuilderBinnedSAH::build<NodeRef>
  224. (
  225. typename BVH::CreateAlloc(bvh),
  226. typename BVH::AlignedNode::Create2(),
  227. typename BVH::AlignedNode::Set2(),
  228. [&] (const BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal2* alloc) -> NodeRef
  229. {
  230. assert(current.prims.size() == 1);
  231. BuildRef* ref = (BuildRef*) prims[current.prims.begin()].ID();
  232. TransformNode* node = (TransformNode*) alloc->alloc0->malloc(sizeof(TransformNode),BVH::byteAlignment);
  233. new (node) TransformNode(ref->local2world,ref->localBounds,ref->node,ref->mask,ref->instID,ref->xfmID,ref->type); // FIXME: rcp should be precalculated somewhere
  234. NodeRef noderef = BVH::encodeNode(node);
  235. noderef.setBarrier();
  236. return noderef;
  237. },
  238. [&] (size_t dn) { bvh->scene->progressMonitor(0); },
  239. prims.data(),pinfo,settings);
  240. bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);
  241. numCollapsedTransformNodes = refs.size();
  242. bvh->root = collapse(bvh->root);
  243. if (scene->device->verbosity(1))
  244. std::cout << "collapsing from " << refs.size() << " to " << numCollapsedTransformNodes << " minimally possible " << nextRef << std::endl;
  245. }
  246. bvh->alloc.cleanup();
  247. bvh->postBuild(t0);
  248. }
  249. template<int N, typename Mesh>
  250. void BVHNBuilderInstancing<N,Mesh>::deleteGeometry(size_t geomID)
  251. {
  252. if (geomID >= objects.size()) return;
  253. delete builders[geomID]; builders[geomID] = nullptr;
  254. delete objects [geomID]; objects [geomID] = nullptr;
  255. }
  256. template<int N, typename Mesh>
  257. void BVHNBuilderInstancing<N,Mesh>::clear()
  258. {
  259. for (size_t i=0; i<objects.size(); i++)
  260. if (objects[i]) objects[i]->clear();
  261. for (size_t i=0; i<builders.size(); i++)
  262. if (builders[i]) builders[i]->clear();
  263. refs.clear();
  264. }
  265. template<int N, typename Mesh>
  266. void BVHNBuilderInstancing<N,Mesh>::open(size_t numInstancedPrimitives)
  267. {
  268. if (refs.size() == 0)
  269. return;
  270. if (scene->device->benchmark) { std::cout << "BENCHMARK_INSTANCES " << refs.size() << std::endl; }
  271. if (scene->device->benchmark) { std::cout << "BENCHMARK_INSTANCED_PRIMITIVES " << numInstancedPrimitives << std::endl; }
  272. /* calculate opening size */
  273. size_t num = 0;
  274. if (scene->device->instancing_block_size ) num = numInstancedPrimitives/scene->device->instancing_block_size;
  275. else if (scene->device->instancing_open_factor != 0.0f) num = scene->device->instancing_open_factor*refs.size();
  276. num = max(num,scene->device->instancing_open_min);
  277. num = min(num,scene->device->instancing_open_max);
  278. refs.reserve(num);
  279. std::make_heap(refs.begin(),refs.end());
  280. while (refs.size()+N-1 <= num)
  281. {
  282. std::pop_heap (refs.begin(),refs.end());
  283. BuildRef ref = refs.back();
  284. refs.pop_back();
  285. if (ref.depth >= scene->device->instancing_open_max_depth) {
  286. ref.clearArea();
  287. refs.push_back(ref);
  288. std::push_heap (refs.begin(),refs.end());
  289. continue;
  290. }
  291. if (ref.node.isAlignedNode())
  292. {
  293. AlignedNode* node = ref.node.alignedNode();
  294. for (size_t i=0; i<N; i++) {
  295. if (node->child(i) == BVH::emptyNode) continue;
  296. refs.push_back(BuildRef(ref.local2world,node->bounds(i),node->child(i),ref.mask,ref.instID,ref.xfmID,ref.type,ref.depth+1));
  297. std::push_heap (refs.begin(),refs.end());
  298. }
  299. }
  300. /*else if (ref.node.isAlignedNodeMB())
  301. {
  302. AlignedNodeMB* node = ref.node.alignedNodeMB();
  303. for (size_t i=0; i<N; i++) {
  304. if (node->child(i) == BVH::emptyNode) continue;
  305. refs.push_back(BuildRef(ref.local2world,node->bounds(i),node->child(i),ref.mask,ref.instID,ref.xfmID,ref.type,ref.depth+1));
  306. std::push_heap (refs.begin(),refs.end());
  307. }
  308. }*/
  309. else {
  310. refs.push_back(ref);
  311. break;
  312. }
  313. }
  314. if (scene->device->benchmark) { std::cout << "BENCHMARK_OPENED_INSTANCES " << refs.size() << std::endl; }
  315. }
  316. template<int N, typename Mesh>
  317. typename BVHNBuilderInstancing<N,Mesh>::NodeRef BVHNBuilderInstancing<N,Mesh>::collapse(NodeRef& node)
  318. {
  319. if (node.isBarrier()) {
  320. node.clearBarrier();
  321. return node;
  322. }
  323. assert(node.isAlignedNode());
  324. AlignedNode* n = node.alignedNode();
  325. TransformNode* first = nullptr;
  326. for (size_t c=0; c<N; c++) {
  327. if (n->child(c) == BVH::emptyNode) continue;
  328. NodeRef child = n->child(c) = collapse(n->child(c));
  329. if (child.isTransformNode()) first = child.transformNode();
  330. }
  331. bool allEqual = true;
  332. for (size_t c=0; c<N; c++)
  333. {
  334. NodeRef child = n->child(c);
  335. if (child == BVH::emptyNode) continue;
  336. if (!child.isTransformNode()) {
  337. allEqual = false;
  338. break;
  339. }
  340. if (child.transformNode()->world2local != first->world2local) {
  341. allEqual = false;
  342. break;
  343. }
  344. if (child.transformNode()->instID != first->instID) {
  345. allEqual = false;
  346. break;
  347. }
  348. }
  349. if (!allEqual)
  350. return node;
  351. BBox3fa bounds = empty;
  352. for (size_t c=0; c<N; c++) {
  353. if (n->child(c) == BVH::emptyNode) continue;
  354. TransformNode* child = n->child(c).transformNode();
  355. numCollapsedTransformNodes--;
  356. const BBox3fa cbounds = child->localBounds;
  357. n->set(c,cbounds,child->child);
  358. bounds.extend(cbounds);
  359. }
  360. numCollapsedTransformNodes++;
  361. first->localBounds = bounds;
  362. first->child = node;
  363. return BVH::encodeNode(first);
  364. }
  365. Builder* BVH4BuilderInstancingTriangleMeshSAH (void* bvh, Scene* scene, const createTriangleMeshAccelTy createTriangleMeshAccel) {
  366. return new BVHNBuilderInstancing<4,TriangleMesh>((BVH4*)bvh,scene,createTriangleMeshAccel);
  367. }
  368. Builder* BVH4BuilderInstancingQuadMeshSAH (void* bvh, Scene* scene, const createQuadMeshAccelTy createQuadMeshAccel) {
  369. return new BVHNBuilderInstancing<4,QuadMesh>((BVH4*)bvh,scene,createQuadMeshAccel);
  370. }
  371. }
  372. }