rtcore_builder.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #define RTC_EXPORT_API
  4. #include "default.h"
  5. #include "device.h"
  6. #include "scene.h"
  7. #include "context.h"
  8. #include "alloc.h"
  9. #include "../builders/bvh_builder_sah.h"
  10. #include "../builders/bvh_builder_morton.h"
  11. namespace embree
  12. {
  13. namespace isa // FIXME: support more ISAs for builders
  14. {
  15. struct BVH : public RefCount
  16. {
  17. BVH (Device* device)
  18. : device(device), allocator(device,true), morton_src(device,0), morton_tmp(device,0)
  19. {
  20. device->refInc();
  21. }
  22. ~BVH() {
  23. device->refDec();
  24. }
  25. public:
  26. Device* device;
  27. FastAllocator allocator;
  28. mvector<BVHBuilderMorton::BuildPrim> morton_src;
  29. mvector<BVHBuilderMorton::BuildPrim> morton_tmp;
  30. };
  31. void* rtcBuildBVHMorton(const RTCBuildArguments* arguments)
  32. {
  33. BVH* bvh = (BVH*) arguments->bvh;
  34. RTCBuildPrimitive* prims_i = arguments->primitives;
  35. size_t primitiveCount = arguments->primitiveCount;
  36. RTCCreateNodeFunction createNode = arguments->createNode;
  37. RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
  38. RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
  39. RTCCreateLeafFunction createLeaf = arguments->createLeaf;
  40. RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
  41. void* userPtr = arguments->userPtr;
  42. std::atomic<size_t> progress(0);
  43. /* initialize temporary arrays for morton builder */
  44. PrimRef* prims = (PrimRef*) prims_i;
  45. mvector<BVHBuilderMorton::BuildPrim>& morton_src = bvh->morton_src;
  46. mvector<BVHBuilderMorton::BuildPrim>& morton_tmp = bvh->morton_tmp;
  47. morton_src.resize(primitiveCount);
  48. morton_tmp.resize(primitiveCount);
  49. /* compute centroid bounds */
  50. const BBox3fa centBounds = parallel_reduce ( size_t(0), primitiveCount, BBox3fa(empty), [&](const range<size_t>& r) -> BBox3fa {
  51. BBox3fa bounds(empty);
  52. for (size_t i=r.begin(); i<r.end(); i++)
  53. bounds.extend(prims[i].bounds().center2());
  54. return bounds;
  55. }, BBox3fa::merge);
  56. /* compute morton codes */
  57. BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
  58. parallel_for ( size_t(0), primitiveCount, [&](const range<size_t>& r) {
  59. BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton_src[r.begin()]);
  60. for (size_t i=r.begin(); i<r.end(); i++) {
  61. generator(prims[i].bounds(),(unsigned) i);
  62. }
  63. });
  64. /* start morton build */
  65. std::pair<void*,BBox3fa> root = BVHBuilderMorton::build<std::pair<void*,BBox3fa>>(
  66. /* thread local allocator for fast allocations */
  67. [&] () -> FastAllocator::CachedAllocator {
  68. return bvh->allocator.getCachedAllocator();
  69. },
  70. /* lambda function that allocates BVH nodes */
  71. [&] ( const FastAllocator::CachedAllocator& alloc, size_t N ) -> void* {
  72. return createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
  73. },
  74. /* lambda function that sets bounds */
  75. [&] (void* node, const std::pair<void*,BBox3fa>* children, size_t N) -> std::pair<void*,BBox3fa>
  76. {
  77. BBox3fa bounds = empty;
  78. void* childptrs[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
  79. const RTCBounds* cbounds[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
  80. for (size_t i=0; i<N; i++) {
  81. bounds.extend(children[i].second);
  82. childptrs[i] = children[i].first;
  83. cbounds[i] = (const RTCBounds*)&children[i].second;
  84. }
  85. setNodeBounds(node,cbounds,(unsigned int)N,userPtr);
  86. setNodeChildren(node,childptrs, (unsigned int)N,userPtr);
  87. return std::make_pair(node,bounds);
  88. },
  89. /* lambda function that creates BVH leaves */
  90. [&]( const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc) -> std::pair<void*,BBox3fa>
  91. {
  92. RTCBuildPrimitive localBuildPrims[RTC_BUILD_MAX_PRIMITIVES_PER_LEAF];
  93. BBox3fa bounds = empty;
  94. for (size_t i=0;i<current.size();i++)
  95. {
  96. const size_t id = morton_src[current.begin()+i].index;
  97. bounds.extend(prims[id].bounds());
  98. localBuildPrims[i] = prims_i[id];
  99. }
  100. void* node = createLeaf((RTCThreadLocalAllocator)&alloc,localBuildPrims,current.size(),userPtr);
  101. return std::make_pair(node,bounds);
  102. },
  103. /* lambda that calculates the bounds for some primitive */
  104. [&] (const BVHBuilderMorton::BuildPrim& morton) -> BBox3fa {
  105. return prims[morton.index].bounds();
  106. },
  107. /* progress monitor function */
  108. [&] (size_t dn) {
  109. if (!buildProgress) return true;
  110. const size_t n = progress.fetch_add(dn)+dn;
  111. const double f = std::min(1.0,double(n)/double(primitiveCount));
  112. return buildProgress(userPtr,f);
  113. },
  114. morton_src.data(),morton_tmp.data(),primitiveCount,
  115. *arguments);
  116. bvh->allocator.cleanup();
  117. return root.first;
  118. }
  119. void* rtcBuildBVHBinnedSAH(const RTCBuildArguments* arguments)
  120. {
  121. BVH* bvh = (BVH*) arguments->bvh;
  122. RTCBuildPrimitive* prims = arguments->primitives;
  123. size_t primitiveCount = arguments->primitiveCount;
  124. RTCCreateNodeFunction createNode = arguments->createNode;
  125. RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
  126. RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
  127. RTCCreateLeafFunction createLeaf = arguments->createLeaf;
  128. RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
  129. void* userPtr = arguments->userPtr;
  130. std::atomic<size_t> progress(0);
  131. /* calculate priminfo */
  132. auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
  133. {
  134. CentGeomBBox3fa bounds(empty);
  135. for (size_t j=r.begin(); j<r.end(); j++)
  136. bounds.extend((BBox3fa&)prims[j]);
  137. return bounds;
  138. };
  139. const CentGeomBBox3fa bounds =
  140. parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
  141. const PrimInfo pinfo(0,primitiveCount,bounds);
  142. /* build BVH */
  143. void* root = BVHBuilderBinnedSAH::build<void*>(
  144. /* thread local allocator for fast allocations */
  145. [&] () -> FastAllocator::CachedAllocator {
  146. return bvh->allocator.getCachedAllocator();
  147. },
  148. /* lambda function that creates BVH nodes */
  149. [&](BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
  150. {
  151. void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
  152. const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
  153. for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
  154. setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
  155. return node;
  156. },
  157. /* lambda function that updates BVH nodes */
  158. [&](const BVHBuilderBinnedSAH::BuildRecord& precord, const BVHBuilderBinnedSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
  159. setNodeChildren(node,children, (unsigned int)N,userPtr);
  160. return node;
  161. },
  162. /* lambda function that creates BVH leaves */
  163. [&](const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
  164. return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
  165. },
  166. /* progress monitor function */
  167. [&] (size_t dn) {
  168. if (!buildProgress) return true;
  169. const size_t n = progress.fetch_add(dn)+dn;
  170. const double f = std::min(1.0,double(n)/double(primitiveCount));
  171. return buildProgress(userPtr,f);
  172. },
  173. (PrimRef*)prims,pinfo,*arguments);
  174. bvh->allocator.cleanup();
  175. return root;
  176. }
  177. static __forceinline const std::pair<CentGeomBBox3fa,unsigned int> mergePair(const std::pair<CentGeomBBox3fa,unsigned int>& a, const std::pair<CentGeomBBox3fa,unsigned int>& b) {
  178. CentGeomBBox3fa centBounds = CentGeomBBox3fa::merge2(a.first,b.first);
  179. unsigned int maxGeomID = max(a.second,b.second);
  180. return std::pair<CentGeomBBox3fa,unsigned int>(centBounds,maxGeomID);
  181. }
  182. void* rtcBuildBVHSpatialSAH(const RTCBuildArguments* arguments)
  183. {
  184. BVH* bvh = (BVH*) arguments->bvh;
  185. RTCBuildPrimitive* prims = arguments->primitives;
  186. size_t primitiveCount = arguments->primitiveCount;
  187. RTCCreateNodeFunction createNode = arguments->createNode;
  188. RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
  189. RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
  190. RTCCreateLeafFunction createLeaf = arguments->createLeaf;
  191. RTCSplitPrimitiveFunction splitPrimitive = arguments->splitPrimitive;
  192. RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
  193. void* userPtr = arguments->userPtr;
  194. std::atomic<size_t> progress(0);
  195. /* calculate priminfo */
  196. auto computeBounds = [&](const range<size_t>& r) -> std::pair<CentGeomBBox3fa,unsigned int>
  197. {
  198. CentGeomBBox3fa bounds(empty);
  199. unsigned maxGeomID = 0;
  200. for (size_t j=r.begin(); j<r.end(); j++)
  201. {
  202. bounds.extend((BBox3fa&)prims[j]);
  203. maxGeomID = max(maxGeomID,prims[j].geomID);
  204. }
  205. return std::pair<CentGeomBBox3fa,unsigned int>(bounds,maxGeomID);
  206. };
  207. const std::pair<CentGeomBBox3fa,unsigned int> pair =
  208. parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),std::pair<CentGeomBBox3fa,unsigned int>(CentGeomBBox3fa(empty),0), computeBounds, mergePair);
  209. CentGeomBBox3fa bounds = pair.first;
  210. const unsigned int maxGeomID = pair.second;
  211. if (unlikely(maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS))))
  212. {
  213. /* fallback code for max geomID larger than threshold */
  214. return rtcBuildBVHBinnedSAH(arguments);
  215. }
  216. const PrimInfo pinfo(0,primitiveCount,bounds);
  217. /* function that splits a build primitive */
  218. struct Splitter
  219. {
  220. Splitter (RTCSplitPrimitiveFunction splitPrimitive, unsigned geomID, unsigned primID, void* userPtr)
  221. : splitPrimitive(splitPrimitive), geomID(geomID), primID(primID), userPtr(userPtr) {}
  222. __forceinline void operator() (PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const
  223. {
  224. prim.geomIDref() &= BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK;
  225. splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
  226. left_o.geomIDref() = geomID; left_o.primIDref() = primID;
  227. right_o.geomIDref() = geomID; right_o.primIDref() = primID;
  228. }
  229. __forceinline void operator() (const BBox3fa& box, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const
  230. {
  231. PrimRef prim(box,geomID & BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK,primID);
  232. splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
  233. }
  234. RTCSplitPrimitiveFunction splitPrimitive;
  235. unsigned geomID;
  236. unsigned primID;
  237. void* userPtr;
  238. };
  239. /* build BVH */
  240. void* root = BVHBuilderBinnedFastSpatialSAH::build<void*>(
  241. /* thread local allocator for fast allocations */
  242. [&] () -> FastAllocator::CachedAllocator {
  243. return bvh->allocator.getCachedAllocator();
  244. },
  245. /* lambda function that creates BVH nodes */
  246. [&] (BVHBuilderBinnedFastSpatialSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
  247. {
  248. void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
  249. const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
  250. for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
  251. setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
  252. return node;
  253. },
  254. /* lambda function that updates BVH nodes */
  255. [&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& precord, const BVHBuilderBinnedFastSpatialSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
  256. setNodeChildren(node,children, (unsigned int)N,userPtr);
  257. return node;
  258. },
  259. /* lambda function that creates BVH leaves */
  260. [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
  261. return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
  262. },
  263. /* returns the splitter */
  264. [&] ( const PrimRef& prim ) -> Splitter {
  265. return Splitter(splitPrimitive,prim.geomID(),prim.primID(),userPtr);
  266. },
  267. /* progress monitor function */
  268. [&] (size_t dn) {
  269. if (!buildProgress) return true;
  270. const size_t n = progress.fetch_add(dn)+dn;
  271. const double f = std::min(1.0,double(n)/double(primitiveCount));
  272. return buildProgress(userPtr,f);
  273. },
  274. (PrimRef*)prims,
  275. arguments->primitiveArrayCapacity,
  276. pinfo,*arguments);
  277. bvh->allocator.cleanup();
  278. return root;
  279. }
  280. }
  281. }
  282. using namespace embree;
  283. using namespace embree::isa;
  284. RTC_NAMESPACE_BEGIN
  285. RTC_API RTCBVH rtcNewBVH(RTCDevice device)
  286. {
  287. RTC_CATCH_BEGIN;
  288. RTC_TRACE(rtcNewAllocator);
  289. RTC_VERIFY_HANDLE(device);
  290. BVH* bvh = new BVH((Device*)device);
  291. return (RTCBVH) bvh->refInc();
  292. RTC_CATCH_END((Device*)device);
  293. return nullptr;
  294. }
  295. RTC_API void* rtcBuildBVH(const RTCBuildArguments* arguments)
  296. {
  297. BVH* bvh = (BVH*) arguments->bvh;
  298. RTC_CATCH_BEGIN;
  299. RTC_TRACE(rtcBuildBVH);
  300. RTC_VERIFY_HANDLE(bvh);
  301. RTC_VERIFY_HANDLE(arguments);
  302. RTC_VERIFY_HANDLE(arguments->createNode);
  303. RTC_VERIFY_HANDLE(arguments->setNodeChildren);
  304. RTC_VERIFY_HANDLE(arguments->setNodeBounds);
  305. RTC_VERIFY_HANDLE(arguments->createLeaf);
  306. if (arguments->primitiveArrayCapacity < arguments->primitiveCount)
  307. throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")
  308. /* initialize the allocator */
  309. bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));
  310. bvh->allocator.reset();
  311. /* switch between different builders based on quality level */
  312. if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)
  313. return rtcBuildBVHMorton(arguments);
  314. else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM)
  315. return rtcBuildBVHBinnedSAH(arguments);
  316. else if (arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) {
  317. if (arguments->splitPrimitive == nullptr || arguments->primitiveArrayCapacity <= arguments->primitiveCount)
  318. return rtcBuildBVHBinnedSAH(arguments);
  319. else
  320. return rtcBuildBVHSpatialSAH(arguments);
  321. }
  322. else
  323. throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid build quality");
  324. /* if we are in dynamic mode, then do not clear temporary data */
  325. if (!(arguments->buildFlags & RTC_BUILD_FLAG_DYNAMIC))
  326. {
  327. bvh->morton_src.clear();
  328. bvh->morton_tmp.clear();
  329. }
  330. RTC_CATCH_END(bvh->device);
  331. return nullptr;
  332. }
  333. RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)
  334. {
  335. FastAllocator::CachedAllocator* alloc = (FastAllocator::CachedAllocator*) localAllocator;
  336. RTC_CATCH_BEGIN;
  337. RTC_TRACE(rtcThreadLocalAlloc);
  338. return alloc->malloc0(bytes,align);
  339. RTC_CATCH_END(alloc->alloc->getDevice());
  340. return nullptr;
  341. }
  342. RTC_API void rtcMakeStaticBVH(RTCBVH hbvh)
  343. {
  344. BVH* bvh = (BVH*) hbvh;
  345. RTC_CATCH_BEGIN;
  346. RTC_TRACE(rtcStaticBVH);
  347. RTC_VERIFY_HANDLE(hbvh);
  348. bvh->morton_src.clear();
  349. bvh->morton_tmp.clear();
  350. RTC_CATCH_END(bvh->device);
  351. }
  352. RTC_API void rtcRetainBVH(RTCBVH hbvh)
  353. {
  354. BVH* bvh = (BVH*) hbvh;
  355. Device* device = bvh ? bvh->device : nullptr;
  356. RTC_CATCH_BEGIN;
  357. RTC_TRACE(rtcRetainBVH);
  358. RTC_VERIFY_HANDLE(hbvh);
  359. bvh->refInc();
  360. RTC_CATCH_END(device);
  361. }
  362. RTC_API void rtcReleaseBVH(RTCBVH hbvh)
  363. {
  364. BVH* bvh = (BVH*) hbvh;
  365. Device* device = bvh ? bvh->device : nullptr;
  366. RTC_CATCH_BEGIN;
  367. RTC_TRACE(rtcReleaseBVH);
  368. RTC_VERIFY_HANDLE(hbvh);
  369. bvh->refDec();
  370. RTC_CATCH_END(device);
  371. }
  372. RTC_NAMESPACE_END