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