rtcore_builder.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. #ifdef _WIN32
  17. # define RTCORE_API extern "C" __declspec(dllexport)
  18. #else
  19. # define RTCORE_API extern "C" __attribute__ ((visibility ("default")))
  20. #endif
  21. #include "default.h"
  22. #include "device.h"
  23. #include "scene.h"
  24. #include "context.h"
  25. #include "alloc.h"
  26. #include "../builders/bvh_builder_sah.h"
  27. #include "../builders/bvh_builder_morton.h"
  28. namespace embree
  29. {
  30. namespace isa // FIXME: support more ISAs for builders
  31. {
  32. struct BVH
  33. {
  34. BVH (Device* device)
  35. : device(device), isStatic(false), allocator(device,true), morton_src(device), morton_tmp(device) {}
  36. public:
  37. Device* device;
  38. bool isStatic;
  39. FastAllocator allocator;
  40. mvector<BVHBuilderMorton::BuildPrim> morton_src;
  41. mvector<BVHBuilderMorton::BuildPrim> morton_tmp;
  42. };
  43. RTCORE_API RTCBVH rtcNewBVH(RTCDevice device)
  44. {
  45. RTCORE_CATCH_BEGIN;
  46. RTCORE_TRACE(rtcNewAllocator);
  47. RTCORE_VERIFY_HANDLE(device);
  48. return (RTCBVH) new BVH((Device*)device);
  49. RTCORE_CATCH_END((Device*)device);
  50. return nullptr;
  51. }
  52. void* rtcBuildBVHMorton(BVH* bvh,
  53. const RTCBuildSettings& settings,
  54. RTCBuildPrimitive* prims_i,
  55. size_t numPrimitives,
  56. RTCCreateNodeFunc createNode,
  57. RTCSetNodeChildrenFunc setNodeChildren,
  58. RTCSetNodeBoundsFunc setNodeBounds,
  59. RTCCreateLeafFunc createLeaf,
  60. RTCBuildProgressFunc buildProgress,
  61. void* userPtr)
  62. {
  63. /* initialize temporary arrays for morton builder */
  64. PrimRef* prims = (PrimRef*) prims_i;
  65. mvector<BVHBuilderMorton::BuildPrim>& morton_src = bvh->morton_src;
  66. mvector<BVHBuilderMorton::BuildPrim>& morton_tmp = bvh->morton_tmp;
  67. morton_src.resize(numPrimitives);
  68. morton_tmp.resize(numPrimitives);
  69. /* compute centroid bounds */
  70. const BBox3fa centBounds = parallel_reduce ( size_t(0), numPrimitives, BBox3fa(empty), [&](const range<size_t>& r) -> BBox3fa {
  71. BBox3fa bounds(empty);
  72. for (size_t i=r.begin(); i<r.end(); i++)
  73. bounds.extend(prims[i].bounds().center2());
  74. return bounds;
  75. }, BBox3fa::merge);
  76. /* compute morton codes */
  77. BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
  78. parallel_for ( size_t(0), numPrimitives, [&](const range<size_t>& r) {
  79. BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton_src[r.begin()]);
  80. for (size_t i=r.begin(); i<r.end(); i++) {
  81. generator(prims[i].bounds(),(unsigned) i);
  82. }
  83. });
  84. /* start morton build */
  85. std::pair<void*,BBox3fa> root = BVHBuilderMorton::build<std::pair<void*,BBox3fa>>(
  86. /* thread local allocator for fast allocations */
  87. [&] () -> FastAllocator::ThreadLocal* {
  88. return bvh->allocator.threadLocal();
  89. },
  90. /* lambda function that allocates BVH nodes */
  91. [&] ( FastAllocator::ThreadLocal* alloc, size_t N ) -> void* {
  92. return createNode((RTCThreadLocalAllocator)alloc,N,userPtr);
  93. },
  94. /* lambda function that sets bounds */
  95. [&] (void* node, const std::pair<void*,BBox3fa>* children, size_t N) -> std::pair<void*,BBox3fa>
  96. {
  97. BBox3fa bounds = empty;
  98. void* childptrs[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
  99. const RTCBounds* cbounds[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
  100. for (size_t i=0; i<N; i++) {
  101. bounds.extend(children[i].second);
  102. childptrs[i] = children[i].first;
  103. cbounds[i] = (const RTCBounds*)&children[i].second;
  104. }
  105. setNodeBounds(node,cbounds,N,userPtr);
  106. setNodeChildren(node,childptrs,N,userPtr);
  107. return std::make_pair(node,bounds);
  108. },
  109. /* lambda function that creates BVH leaves */
  110. [&]( const range<unsigned>& current, FastAllocator::ThreadLocal* alloc) -> std::pair<void*,BBox3fa>
  111. {
  112. const size_t id = morton_src[current.begin()].index;
  113. const BBox3fa bounds = prims[id].bounds();
  114. void* node = createLeaf((RTCThreadLocalAllocator)alloc,prims_i+current.begin(),current.size(),userPtr);
  115. return std::make_pair(node,bounds);
  116. },
  117. /* lambda that calculates the bounds for some primitive */
  118. [&] (const BVHBuilderMorton::BuildPrim& morton) -> BBox3fa {
  119. return prims[morton.index].bounds();
  120. },
  121. /* progress monitor function */
  122. [&] (size_t dn) {
  123. if (buildProgress) buildProgress(dn,userPtr);
  124. },
  125. morton_src.data(),morton_tmp.data(),numPrimitives,
  126. settings);
  127. bvh->allocator.cleanup();
  128. return root.first;
  129. }
  130. void* rtcBuildBVHBinnedSAH(BVH* bvh,
  131. const RTCBuildSettings& settings,
  132. RTCBuildPrimitive* prims,
  133. size_t numPrimitives,
  134. RTCCreateNodeFunc createNode,
  135. RTCSetNodeChildrenFunc setNodeChildren,
  136. RTCSetNodeBoundsFunc setNodeBounds,
  137. RTCCreateLeafFunc createLeaf,
  138. RTCBuildProgressFunc buildProgress,
  139. void* userPtr)
  140. {
  141. /* calculate priminfo */
  142. auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
  143. {
  144. CentGeomBBox3fa bounds(empty);
  145. for (size_t j=r.begin(); j<r.end(); j++)
  146. bounds.extend((BBox3fa&)prims[j]);
  147. return bounds;
  148. };
  149. const CentGeomBBox3fa bounds =
  150. parallel_reduce(size_t(0),numPrimitives,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
  151. const PrimInfo pinfo(0,numPrimitives,bounds.geomBounds,bounds.centBounds);
  152. /* build BVH */
  153. void* root = BVHBuilderBinnedSAH::build<void*>(
  154. /* thread local allocator for fast allocations */
  155. [&] () -> FastAllocator::ThreadLocal* {
  156. return bvh->allocator.threadLocal();
  157. },
  158. /* lambda function that creates BVH nodes */
  159. [&](BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal* alloc) -> void*
  160. {
  161. void* node = createNode((RTCThreadLocalAllocator)alloc,N,userPtr);
  162. const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
  163. for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
  164. setNodeBounds(node,cbounds,N,userPtr);
  165. return node;
  166. },
  167. /* lambda function that updates BVH nodes */
  168. [&](const BVHBuilderBinnedSAH::BuildRecord& precord, const BVHBuilderBinnedSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
  169. setNodeChildren(node,children,N,userPtr);
  170. return node;
  171. },
  172. /* lambda function that creates BVH leaves */
  173. [&](const BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal* alloc) -> void* {
  174. return createLeaf((RTCThreadLocalAllocator)alloc,prims+current.prims.begin(),current.prims.size(),userPtr);
  175. },
  176. /* progress monitor function */
  177. [&] (size_t dn) {
  178. if (buildProgress) buildProgress(dn,userPtr);
  179. },
  180. (PrimRef*)prims,pinfo,settings);
  181. bvh->allocator.cleanup();
  182. return root;
  183. }
  184. void* rtcBuildBVHSpatialSAH(BVH* bvh,
  185. const RTCBuildSettings& settings,
  186. RTCBuildPrimitive* prims,
  187. size_t numPrimitives,
  188. RTCCreateNodeFunc createNode,
  189. RTCSetNodeChildrenFunc setNodeChildren,
  190. RTCSetNodeBoundsFunc setNodeBounds,
  191. RTCCreateLeafFunc createLeaf,
  192. RTCSplitPrimitiveFunc splitPrimitive,
  193. RTCBuildProgressFunc buildProgress,
  194. void* userPtr)
  195. {
  196. /* calculate priminfo */
  197. auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
  198. {
  199. CentGeomBBox3fa bounds(empty);
  200. for (size_t j=r.begin(); j<r.end(); j++)
  201. bounds.extend((BBox3fa&)prims[j]);
  202. return bounds;
  203. };
  204. const CentGeomBBox3fa bounds =
  205. parallel_reduce(size_t(0),numPrimitives,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
  206. const PrimInfo pinfo(0,numPrimitives,bounds.geomBounds,bounds.centBounds);
  207. /* function that splits a build primitive */
  208. struct Splitter
  209. {
  210. Splitter (RTCSplitPrimitiveFunc splitPrimitive, unsigned geomID, unsigned primID, void* userPtr)
  211. : splitPrimitive(splitPrimitive), geomID(geomID), primID(primID), userPtr(userPtr) {}
  212. __forceinline void operator() (PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const
  213. {
  214. prim.geomID() &= BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK;
  215. splitPrimitive((RTCBuildPrimitive&)prim,dim,pos,(RTCBounds&)left_o,(RTCBounds&)right_o,userPtr);
  216. left_o.geomID() = geomID; left_o.primID() = primID;
  217. right_o.geomID() = geomID; right_o.primID() = primID;
  218. }
  219. __forceinline void operator() (const BBox3fa& box, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const
  220. {
  221. PrimRef prim(box,geomID & BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK,primID);
  222. splitPrimitive((RTCBuildPrimitive&)prim,dim,pos,(RTCBounds&)left_o,(RTCBounds&)right_o,userPtr);
  223. }
  224. RTCSplitPrimitiveFunc splitPrimitive;
  225. unsigned geomID;
  226. unsigned primID;
  227. void* userPtr;
  228. };
  229. /* build BVH */
  230. void* root = BVHBuilderBinnedFastSpatialSAH::build<void*>(
  231. /* thread local allocator for fast allocations */
  232. [&] () -> FastAllocator::ThreadLocal* {
  233. return bvh->allocator.threadLocal();
  234. },
  235. /* lambda function that creates BVH nodes */
  236. [&] (BVHBuilderBinnedFastSpatialSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal* alloc) -> void*
  237. {
  238. void* node = createNode((RTCThreadLocalAllocator)alloc,N,userPtr);
  239. const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
  240. for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
  241. setNodeBounds(node,cbounds,N,userPtr);
  242. return node;
  243. },
  244. /* lambda function that updates BVH nodes */
  245. [&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& precord, const BVHBuilderBinnedFastSpatialSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
  246. setNodeChildren(node,children,N,userPtr);
  247. return node;
  248. },
  249. /* lambda function that creates BVH leaves */
  250. [&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& current, FastAllocator::ThreadLocal* alloc) -> void* {
  251. return createLeaf((RTCThreadLocalAllocator)alloc,prims+current.prims.begin(),current.prims.size(),userPtr);
  252. },
  253. /* returns the splitter */
  254. [&] ( const PrimRef& prim ) -> Splitter {
  255. return Splitter(splitPrimitive,prim.geomID(),prim.primID(),userPtr);
  256. },
  257. /* progress monitor function */
  258. [&] (size_t dn) {
  259. if (buildProgress) buildProgress(dn,userPtr);
  260. },
  261. (PrimRef*)prims,
  262. pinfo.size()+settings.extraSpace,
  263. pinfo,settings);
  264. bvh->allocator.cleanup();
  265. return root;
  266. }
  267. RTCORE_API void* rtcBuildBVH(RTCBVH hbvh,
  268. const RTCBuildSettings& settings,
  269. RTCBuildPrimitive* prims,
  270. size_t numPrimitives,
  271. RTCCreateNodeFunc createNode,
  272. RTCSetNodeChildrenFunc setNodeChildren,
  273. RTCSetNodeBoundsFunc setNodeBounds,
  274. RTCCreateLeafFunc createLeaf,
  275. RTCSplitPrimitiveFunc splitPrimitive,
  276. RTCBuildProgressFunc buildProgress,
  277. void* userPtr)
  278. {
  279. BVH* bvh = (BVH*) hbvh;
  280. RTCORE_CATCH_BEGIN;
  281. RTCORE_TRACE(rtcBuildBVH);
  282. RTCORE_VERIFY_HANDLE(hbvh);
  283. RTCORE_VERIFY_HANDLE(createNode);
  284. RTCORE_VERIFY_HANDLE(setNodeChildren);
  285. RTCORE_VERIFY_HANDLE(setNodeBounds);
  286. RTCORE_VERIFY_HANDLE(createLeaf);
  287. /* if we made this BVH static, we can not re-build it anymore */
  288. if (bvh->isStatic)
  289. throw_RTCError(RTC_INVALID_OPERATION,"static BVH cannot get rebuild");
  290. /* initialize the allocator */
  291. bvh->allocator.init_estimate(numPrimitives*sizeof(BBox3fa));
  292. bvh->allocator.reset();
  293. /* switch between differnet builders based on quality level */
  294. if (settings.quality == RTC_BUILD_QUALITY_LOW)
  295. return rtcBuildBVHMorton (bvh,settings,prims,numPrimitives,createNode,setNodeChildren,setNodeBounds,createLeaf,buildProgress,userPtr);
  296. else if (settings.quality == RTC_BUILD_QUALITY_NORMAL)
  297. return rtcBuildBVHBinnedSAH(bvh,settings,prims,numPrimitives,createNode,setNodeChildren,setNodeBounds,createLeaf,buildProgress,userPtr);
  298. else if (settings.quality == RTC_BUILD_QUALITY_HIGH) {
  299. if (splitPrimitive == nullptr || settings.extraSpace == 0)
  300. return rtcBuildBVHBinnedSAH(bvh,settings,prims,numPrimitives,createNode,setNodeChildren,setNodeBounds,createLeaf,buildProgress,userPtr);
  301. else
  302. return rtcBuildBVHSpatialSAH(bvh,settings,prims,numPrimitives,createNode,setNodeChildren,setNodeBounds,createLeaf,splitPrimitive,buildProgress,userPtr);
  303. }
  304. else
  305. throw_RTCError(RTC_INVALID_OPERATION,"invalid build quality");
  306. RTCORE_CATCH_END(bvh->device);
  307. return nullptr;
  308. }
  309. RTCORE_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)
  310. {
  311. RTCORE_CATCH_BEGIN;
  312. RTCORE_TRACE(rtcThreadLocalAlloc);
  313. FastAllocator::ThreadLocal* alloc = (FastAllocator::ThreadLocal*) localAllocator;
  314. return alloc->malloc(bytes,align);
  315. RTCORE_CATCH_END(((FastAllocator::ThreadLocal*) localAllocator)->alloc->getDevice());
  316. return nullptr;
  317. }
  318. RTCORE_API void rtcMakeStaticBVH(RTCBVH hbvh)
  319. {
  320. BVH* bvh = (BVH*) hbvh;
  321. RTCORE_CATCH_BEGIN;
  322. RTCORE_TRACE(rtcStaticBVH);
  323. RTCORE_VERIFY_HANDLE(hbvh);
  324. bvh->allocator.shrink();
  325. bvh->morton_src.clear();
  326. bvh->morton_tmp.clear();
  327. bvh->isStatic = true;
  328. RTCORE_CATCH_END(bvh->device);
  329. }
  330. RTCORE_API void rtcDeleteBVH(RTCBVH hbvh)
  331. {
  332. BVH* bvh = (BVH*) hbvh;
  333. Device* device = bvh ? bvh->device : nullptr;
  334. RTCORE_CATCH_BEGIN;
  335. RTCORE_TRACE(rtcDeleteAllocator);
  336. RTCORE_VERIFY_HANDLE(hbvh);
  337. delete bvh;
  338. RTCORE_CATCH_END(device);
  339. }
  340. }
  341. }