heuristic_spatial_array.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "heuristic_binning.h"
  5. #include "heuristic_spatial.h"
  6. namespace embree
  7. {
  8. namespace isa
  9. {
  10. #if 0
  11. #define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.2f
  12. #define SPATIAL_ASPLIT_SAH_THRESHOLD 0.95f
  13. #define SPATIAL_ASPLIT_AREA_THRESHOLD 0.0f
  14. #else
  15. #define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.1f
  16. #define SPATIAL_ASPLIT_SAH_THRESHOLD 0.99f
  17. #define SPATIAL_ASPLIT_AREA_THRESHOLD 0.000005f
  18. #endif
  19. struct PrimInfoExtRange : public CentGeomBBox3fa, public extended_range<size_t>
  20. {
  21. __forceinline PrimInfoExtRange() {
  22. }
  23. __forceinline PrimInfoExtRange(EmptyTy)
  24. : CentGeomBBox3fa(EmptyTy()), extended_range<size_t>(0,0,0) {}
  25. __forceinline PrimInfoExtRange(size_t begin, size_t end, size_t ext_end, const CentGeomBBox3fa& centGeomBounds)
  26. : CentGeomBBox3fa(centGeomBounds), extended_range<size_t>(begin,end,ext_end) {}
  27. __forceinline float leafSAH() const {
  28. return expectedApproxHalfArea(geomBounds)*float(size());
  29. }
  30. __forceinline float leafSAH(size_t block_shift) const {
  31. return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
  32. }
  33. };
  34. template<typename ObjectSplit, typename SpatialSplit>
  35. struct Split2
  36. {
  37. __forceinline Split2 () {}
  38. __forceinline Split2 (const Split2& other)
  39. {
  40. spatial = other.spatial;
  41. sah = other.sah;
  42. if (spatial) spatialSplit() = other.spatialSplit();
  43. else objectSplit() = other.objectSplit();
  44. }
  45. __forceinline Split2& operator= (const Split2& other)
  46. {
  47. spatial = other.spatial;
  48. sah = other.sah;
  49. if (spatial) spatialSplit() = other.spatialSplit();
  50. else objectSplit() = other.objectSplit();
  51. return *this;
  52. }
  53. __forceinline ObjectSplit& objectSplit() { return *( ObjectSplit*)data; }
  54. __forceinline const ObjectSplit& objectSplit() const { return *(const ObjectSplit*)data; }
  55. __forceinline SpatialSplit& spatialSplit() { return *( SpatialSplit*)data; }
  56. __forceinline const SpatialSplit& spatialSplit() const { return *(const SpatialSplit*)data; }
  57. __forceinline Split2 (const ObjectSplit& objectSplit, float sah)
  58. : spatial(false), sah(sah)
  59. {
  60. new (data) ObjectSplit(objectSplit);
  61. }
  62. __forceinline Split2 (const SpatialSplit& spatialSplit, float sah)
  63. : spatial(true), sah(sah)
  64. {
  65. new (data) SpatialSplit(spatialSplit);
  66. }
  67. __forceinline float splitSAH() const {
  68. return sah;
  69. }
  70. __forceinline bool valid() const {
  71. return sah < float(inf);
  72. }
  73. public:
  74. __aligned(64) char data[sizeof(ObjectSplit) > sizeof(SpatialSplit) ? sizeof(ObjectSplit) : sizeof(SpatialSplit)];
  75. bool spatial;
  76. float sah;
  77. };
  78. /*! Performs standard object binning */
  79. template<typename PrimitiveSplitterFactory, typename PrimRef, size_t OBJECT_BINS, size_t SPATIAL_BINS>
  80. struct HeuristicArraySpatialSAH
  81. {
  82. typedef BinSplit<OBJECT_BINS> ObjectSplit;
  83. typedef BinInfoT<OBJECT_BINS,PrimRef,BBox3fa> ObjectBinner;
  84. typedef SpatialBinSplit<SPATIAL_BINS> SpatialSplit;
  85. typedef SpatialBinInfo<SPATIAL_BINS,PrimRef> SpatialBinner;
  86. //typedef extended_range<size_t> Set;
  87. typedef Split2<ObjectSplit,SpatialSplit> Split;
  88. static const size_t PARALLEL_THRESHOLD = 3*1024;
  89. static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
  90. static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
  91. static const size_t MOVE_STEP_SIZE = 64;
  92. static const size_t CREATE_SPLITS_STEP_SIZE = 64;
  93. __forceinline HeuristicArraySpatialSAH ()
  94. : prims0(nullptr) {}
  95. /*! remember prim array */
  96. __forceinline HeuristicArraySpatialSAH (const PrimitiveSplitterFactory& splitterFactory, PrimRef* prims0, const CentGeomBBox3fa& root_info)
  97. : prims0(prims0), splitterFactory(splitterFactory), root_info(root_info) {}
  98. /*! compute extended ranges */
  99. __noinline void setExtentedRanges(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset, const size_t lweight, const size_t rweight)
  100. {
  101. assert(set.ext_range_size() > 0);
  102. const float left_factor = (float)lweight / (lweight + rweight);
  103. const size_t ext_range_size = set.ext_range_size();
  104. const size_t left_ext_range_size = min((size_t)(floorf(left_factor * ext_range_size)),ext_range_size);
  105. const size_t right_ext_range_size = ext_range_size - left_ext_range_size;
  106. lset.set_ext_range(lset.end() + left_ext_range_size);
  107. rset.set_ext_range(rset.end() + right_ext_range_size);
  108. }
  109. /*! move ranges */
  110. __noinline void moveExtentedRange(const PrimInfoExtRange& set, const PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  111. {
  112. const size_t left_ext_range_size = lset.ext_range_size();
  113. const size_t right_size = rset.size();
  114. /* has the left child an extended range? */
  115. if (left_ext_range_size > 0)
  116. {
  117. /* left extended range smaller than right range ? */
  118. if (left_ext_range_size < right_size)
  119. {
  120. /* only move a small part of the beginning of the right range to the end */
  121. parallel_for( rset.begin(), rset.begin()+left_ext_range_size, MOVE_STEP_SIZE, [&](const range<size_t>& r) {
  122. for (size_t i=r.begin(); i<r.end(); i++)
  123. prims0[i+right_size] = prims0[i];
  124. });
  125. }
  126. else
  127. {
  128. /* no overlap, move entire right range to new location, can be made fully parallel */
  129. parallel_for( rset.begin(), rset.end(), MOVE_STEP_SIZE, [&](const range<size_t>& r) {
  130. for (size_t i=r.begin(); i<r.end(); i++)
  131. prims0[i+left_ext_range_size] = prims0[i];
  132. });
  133. }
  134. /* update right range */
  135. assert(rset.ext_end() + left_ext_range_size == set.ext_end());
  136. rset.move_right(left_ext_range_size);
  137. }
  138. }
  139. /*! finds the best split */
  140. const Split find(const PrimInfoExtRange& set, const size_t logBlockSize)
  141. {
  142. SplitInfo oinfo;
  143. const ObjectSplit object_split = object_find(set,logBlockSize,oinfo);
  144. const float object_split_sah = object_split.splitSAH();
  145. if (unlikely(set.has_ext_range()))
  146. {
  147. const BBox3fa overlap = intersect(oinfo.leftBounds, oinfo.rightBounds);
  148. /* do only spatial splits if the child bounds overlap */
  149. if (safeArea(overlap) >= SPATIAL_ASPLIT_AREA_THRESHOLD*safeArea(root_info.geomBounds) &&
  150. safeArea(overlap) >= SPATIAL_ASPLIT_OVERLAP_THRESHOLD*safeArea(set.geomBounds))
  151. {
  152. const SpatialSplit spatial_split = spatial_find(set, logBlockSize);
  153. const float spatial_split_sah = spatial_split.splitSAH();
  154. /* valid spatial split, better SAH and number of splits do not exceed extended range */
  155. if (spatial_split_sah < SPATIAL_ASPLIT_SAH_THRESHOLD*object_split_sah &&
  156. spatial_split.left + spatial_split.right - set.size() <= set.ext_range_size())
  157. {
  158. return Split(spatial_split,spatial_split_sah);
  159. }
  160. }
  161. }
  162. return Split(object_split,object_split_sah);
  163. }
  164. /*! finds the best object split */
  165. __forceinline const ObjectSplit object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
  166. {
  167. if (set.size() < PARALLEL_THRESHOLD) return sequential_object_find(set,logBlockSize,info);
  168. else return parallel_object_find (set,logBlockSize,info);
  169. }
  170. /*! finds the best object split */
  171. __noinline const ObjectSplit sequential_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
  172. {
  173. ObjectBinner binner(empty);
  174. const BinMapping<OBJECT_BINS> mapping(set);
  175. binner.bin(prims0,set.begin(),set.end(),mapping);
  176. ObjectSplit s = binner.best(mapping,logBlockSize);
  177. binner.getSplitInfo(mapping, s, info);
  178. return s;
  179. }
  180. /*! finds the best split */
  181. __noinline const ObjectSplit parallel_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
  182. {
  183. ObjectBinner binner(empty);
  184. const BinMapping<OBJECT_BINS> mapping(set);
  185. const BinMapping<OBJECT_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
  186. binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
  187. [&] (const range<size_t>& r) -> ObjectBinner { ObjectBinner binner(empty); binner.bin(prims0+r.begin(),r.size(),_mapping); return binner; },
  188. [&] (const ObjectBinner& b0, const ObjectBinner& b1) -> ObjectBinner { ObjectBinner r = b0; r.merge(b1,_mapping.size()); return r; });
  189. ObjectSplit s = binner.best(mapping,logBlockSize);
  190. binner.getSplitInfo(mapping, s, info);
  191. return s;
  192. }
  193. /*! finds the best spatial split */
  194. __forceinline const SpatialSplit spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
  195. {
  196. if (set.size() < PARALLEL_THRESHOLD) return sequential_spatial_find(set, logBlockSize);
  197. else return parallel_spatial_find (set, logBlockSize);
  198. }
  199. /*! finds the best spatial split */
  200. __noinline const SpatialSplit sequential_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
  201. {
  202. SpatialBinner binner(empty);
  203. const SpatialBinMapping<SPATIAL_BINS> mapping(set);
  204. binner.bin2(splitterFactory,prims0,set.begin(),set.end(),mapping);
  205. /* todo: best spatial split not exceeding the extended range does not provide any benefit ?*/
  206. return binner.best(mapping,logBlockSize); //,set.ext_size());
  207. }
  208. __noinline const SpatialSplit parallel_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
  209. {
  210. SpatialBinner binner(empty);
  211. const SpatialBinMapping<SPATIAL_BINS> mapping(set);
  212. const SpatialBinMapping<SPATIAL_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
  213. binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
  214. [&] (const range<size_t>& r) -> SpatialBinner {
  215. SpatialBinner binner(empty);
  216. binner.bin2(splitterFactory,prims0,r.begin(),r.end(),_mapping);
  217. return binner; },
  218. [&] (const SpatialBinner& b0, const SpatialBinner& b1) -> SpatialBinner { return SpatialBinner::reduce(b0,b1); });
  219. /* todo: best spatial split not exceeding the extended range does not provide any benefit ?*/
  220. return binner.best(mapping,logBlockSize); //,set.ext_size());
  221. }
  222. /*! subdivides primitives based on a spatial split */
  223. __noinline void create_spatial_splits(PrimInfoExtRange& set, const SpatialSplit& split, const SpatialBinMapping<SPATIAL_BINS> &mapping)
  224. {
  225. assert(set.has_ext_range());
  226. const size_t max_ext_range_size = set.ext_range_size();
  227. const size_t ext_range_start = set.end();
  228. /* atomic counter for number of primref splits */
  229. std::atomic<size_t> ext_elements;
  230. ext_elements.store(0);
  231. const float fpos = split.mapping.pos(split.pos,split.dim);
  232. const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
  233. parallel_for( set.begin(), set.end(), CREATE_SPLITS_STEP_SIZE, [&](const range<size_t>& r) {
  234. for (size_t i=r.begin();i<r.end();i++)
  235. {
  236. const unsigned int splits = prims0[i].geomID() >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
  237. if (likely(splits <= 1)) continue; /* todo: does this ever happen ? */
  238. //int bin0 = split.mapping.bin(prims0[i].lower)[split.dim];
  239. //int bin1 = split.mapping.bin(prims0[i].upper)[split.dim];
  240. //if (unlikely(bin0 < split.pos && bin1 >= split.pos))
  241. if (unlikely(prims0[i].lower[split.dim] < fpos && prims0[i].upper[split.dim] > fpos))
  242. {
  243. assert(splits > 1);
  244. PrimRef left,right;
  245. const auto splitter = splitterFactory(prims0[i]);
  246. splitter(prims0[i],split.dim,fpos,left,right);
  247. // no empty splits
  248. if (unlikely(left.bounds().empty() || right.bounds().empty())) continue;
  249. left.lower.u = (left.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
  250. right.lower.u = (right.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
  251. const size_t ID = ext_elements.fetch_add(1);
  252. /* break if the number of subdivided elements are greater than the maximum allowed size */
  253. if (unlikely(ID >= max_ext_range_size))
  254. break;
  255. /* only write within the correct bounds */
  256. assert(ID < max_ext_range_size);
  257. prims0[i] = left;
  258. prims0[ext_range_start+ID] = right;
  259. }
  260. }
  261. });
  262. const size_t numExtElements = min(max_ext_range_size,ext_elements.load());
  263. assert(set.end()+numExtElements<=set.ext_end());
  264. set._end += numExtElements;
  265. }
  266. /*! array partitioning */
  267. void split(const Split& split, const PrimInfoExtRange& set_i, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  268. {
  269. PrimInfoExtRange set = set_i;
  270. /* valid split */
  271. if (unlikely(!split.valid())) {
  272. deterministic_order(set);
  273. return splitFallback(set,lset,rset);
  274. }
  275. std::pair<size_t,size_t> ext_weights(0,0);
  276. if (unlikely(split.spatial))
  277. {
  278. create_spatial_splits(set,split.spatialSplit(), split.spatialSplit().mapping);
  279. /* spatial split */
  280. if (likely(set.size() < PARALLEL_THRESHOLD))
  281. ext_weights = sequential_spatial_split(split.spatialSplit(),set,lset,rset);
  282. else
  283. ext_weights = parallel_spatial_split(split.spatialSplit(),set,lset,rset);
  284. }
  285. else
  286. {
  287. /* object split */
  288. if (likely(set.size() < PARALLEL_THRESHOLD))
  289. ext_weights = sequential_object_split(split.objectSplit(),set,lset,rset);
  290. else
  291. ext_weights = parallel_object_split(split.objectSplit(),set,lset,rset);
  292. }
  293. /* if we have an extended range, set extended child ranges and move right split range */
  294. if (unlikely(set.has_ext_range()))
  295. {
  296. setExtentedRanges(set,lset,rset,ext_weights.first,ext_weights.second);
  297. moveExtentedRange(set,lset,rset);
  298. }
  299. }
  300. /*! array partitioning */
  301. std::pair<size_t,size_t> sequential_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  302. {
  303. const size_t begin = set.begin();
  304. const size_t end = set.end();
  305. PrimInfo local_left(empty);
  306. PrimInfo local_right(empty);
  307. const unsigned int splitPos = split.pos;
  308. const unsigned int splitDim = split.dim;
  309. const unsigned int splitDimMask = (unsigned int)1 << splitDim;
  310. const typename ObjectBinner::vint vSplitPos(splitPos);
  311. const typename ObjectBinner::vbool vSplitMask(splitDimMask);
  312. size_t center = serial_partitioning(prims0,
  313. begin,end,local_left,local_right,
  314. [&] (const PrimRef& ref) {
  315. return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask);
  316. },
  317. [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
  318. const size_t left_weight = local_left.end;
  319. const size_t right_weight = local_right.end;
  320. new (&lset) PrimInfoExtRange(begin,center,center,local_left);
  321. new (&rset) PrimInfoExtRange(center,end,end,local_right);
  322. assert(!lset.geomBounds.empty() && area(lset.geomBounds) >= 0.0f);
  323. assert(!rset.geomBounds.empty() && area(rset.geomBounds) >= 0.0f);
  324. return std::pair<size_t,size_t>(left_weight,right_weight);
  325. }
  326. /*! array partitioning */
  327. __noinline std::pair<size_t,size_t> sequential_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  328. {
  329. const size_t begin = set.begin();
  330. const size_t end = set.end();
  331. PrimInfo local_left(empty);
  332. PrimInfo local_right(empty);
  333. const unsigned int splitPos = split.pos;
  334. const unsigned int splitDim = split.dim;
  335. const unsigned int splitDimMask = (unsigned int)1 << splitDim;
  336. /* init spatial mapping */
  337. const SpatialBinMapping<SPATIAL_BINS> &mapping = split.mapping;
  338. const vint4 vSplitPos(splitPos);
  339. const vbool4 vSplitMask( (int)splitDimMask );
  340. size_t center = serial_partitioning(prims0,
  341. begin,end,local_left,local_right,
  342. [&] (const PrimRef& ref) {
  343. const Vec3fa c = ref.bounds().center();
  344. return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask);
  345. },
  346. [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
  347. const size_t left_weight = local_left.end;
  348. const size_t right_weight = local_right.end;
  349. new (&lset) PrimInfoExtRange(begin,center,center,local_left);
  350. new (&rset) PrimInfoExtRange(center,end,end,local_right);
  351. assert(!lset.geomBounds.empty() && area(lset.geomBounds) >= 0.0f);
  352. assert(!rset.geomBounds.empty() && area(rset.geomBounds) >= 0.0f);
  353. return std::pair<size_t,size_t>(left_weight,right_weight);
  354. }
  355. /*! array partitioning */
  356. __noinline std::pair<size_t,size_t> parallel_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  357. {
  358. const size_t begin = set.begin();
  359. const size_t end = set.end();
  360. PrimInfo left(empty);
  361. PrimInfo right(empty);
  362. const unsigned int splitPos = split.pos;
  363. const unsigned int splitDim = split.dim;
  364. const unsigned int splitDimMask = (unsigned int)1 << splitDim;
  365. const typename ObjectBinner::vint vSplitPos(splitPos);
  366. const typename ObjectBinner::vbool vSplitMask(splitDimMask);
  367. auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
  368. const size_t center = parallel_partitioning(
  369. prims0,begin,end,EmptyTy(),left,right,isLeft,
  370. [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
  371. [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
  372. PARALLEL_PARTITION_BLOCK_SIZE);
  373. const size_t left_weight = left.end;
  374. const size_t right_weight = right.end;
  375. left.begin = begin; left.end = center;
  376. right.begin = center; right.end = end;
  377. new (&lset) PrimInfoExtRange(begin,center,center,left);
  378. new (&rset) PrimInfoExtRange(center,end,end,right);
  379. assert(area(left.geomBounds) >= 0.0f);
  380. assert(area(right.geomBounds) >= 0.0f);
  381. return std::pair<size_t,size_t>(left_weight,right_weight);
  382. }
  383. /*! array partitioning */
  384. __noinline std::pair<size_t,size_t> parallel_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
  385. {
  386. const size_t begin = set.begin();
  387. const size_t end = set.end();
  388. PrimInfo left(empty);
  389. PrimInfo right(empty);
  390. const unsigned int splitPos = split.pos;
  391. const unsigned int splitDim = split.dim;
  392. const unsigned int splitDimMask = (unsigned int)1 << splitDim;
  393. /* init spatial mapping */
  394. const SpatialBinMapping<SPATIAL_BINS>& mapping = split.mapping;
  395. const vint4 vSplitPos(splitPos);
  396. const vbool4 vSplitMask( (int)splitDimMask );
  397. auto isLeft = [&] (const PrimRef &ref) {
  398. const Vec3fa c = ref.bounds().center();
  399. return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask); };
  400. const size_t center = parallel_partitioning(
  401. prims0,begin,end,EmptyTy(),left,right,isLeft,
  402. [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
  403. [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
  404. PARALLEL_PARTITION_BLOCK_SIZE);
  405. const size_t left_weight = left.end;
  406. const size_t right_weight = right.end;
  407. left.begin = begin; left.end = center;
  408. right.begin = center; right.end = end;
  409. new (&lset) PrimInfoExtRange(begin,center,center,left);
  410. new (&rset) PrimInfoExtRange(center,end,end,right);
  411. assert(area(left.geomBounds) >= 0.0f);
  412. assert(area(right.geomBounds) >= 0.0f);
  413. return std::pair<size_t,size_t>(left_weight,right_weight);
  414. }
  415. void deterministic_order(const PrimInfoExtRange& set)
  416. {
  417. /* required as parallel partition destroys original primitive order */
  418. std::sort(&prims0[set.begin()],&prims0[set.end()]);
  419. }
  420. void splitFallback(const PrimInfoExtRange& set,
  421. PrimInfoExtRange& lset,
  422. PrimInfoExtRange& rset)
  423. {
  424. const size_t begin = set.begin();
  425. const size_t end = set.end();
  426. const size_t center = (begin + end)/2;
  427. PrimInfo left(empty);
  428. for (size_t i=begin; i<center; i++) {
  429. left.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
  430. }
  431. const size_t lweight = left.end;
  432. PrimInfo right(empty);
  433. for (size_t i=center; i<end; i++) {
  434. right.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
  435. }
  436. const size_t rweight = right.end;
  437. new (&lset) PrimInfoExtRange(begin,center,center,left);
  438. new (&rset) PrimInfoExtRange(center,end,end,right);
  439. /* if we have an extended range */
  440. if (set.has_ext_range()) {
  441. setExtentedRanges(set,lset,rset,lweight,rweight);
  442. moveExtentedRange(set,lset,rset);
  443. }
  444. }
  445. private:
  446. PrimRef* const prims0;
  447. const PrimitiveSplitterFactory& splitterFactory;
  448. const CentGeomBBox3fa& root_info;
  449. };
  450. }
  451. }