1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #include "bvh.h" |
5 | #include "bvh_builder.h" |
6 | #include "../builders/bvh_builder_msmblur.h" |
7 | |
8 | #include "../builders/primrefgen.h" |
9 | #include "../builders/splitter.h" |
10 | |
11 | #include "../geometry/linei.h" |
12 | #include "../geometry/triangle.h" |
13 | #include "../geometry/trianglev.h" |
14 | #include "../geometry/trianglev_mb.h" |
15 | #include "../geometry/trianglei.h" |
16 | #include "../geometry/quadv.h" |
17 | #include "../geometry/quadi.h" |
18 | #include "../geometry/object.h" |
19 | #include "../geometry/instance.h" |
20 | #include "../geometry/subgrid.h" |
21 | |
22 | #include "../common/state.h" |
23 | |
24 | // FIXME: remove after removing BVHNBuilderMBlurRootTimeSplitsSAH |
25 | #include "../../common/algorithms/parallel_for_for.h" |
26 | #include "../../common/algorithms/parallel_for_for_prefix_sum.h" |
27 | |
28 | |
29 | namespace embree |
30 | { |
31 | namespace isa |
32 | { |
33 | |
34 | #if 0 |
35 | template<int N, typename Primitive> |
36 | struct CreateMBlurLeaf |
37 | { |
38 | typedef BVHN<N> BVH; |
39 | typedef typename BVH::NodeRef NodeRef; |
40 | typedef typename BVH::NodeRecordMB NodeRecordMB; |
41 | |
42 | __forceinline CreateMBlurLeaf (BVH* bvh, PrimRef* prims, size_t time) : bvh(bvh), prims(prims), time(time) {} |
43 | |
44 | __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const |
45 | { |
46 | size_t items = Primitive::blocks(set.size()); |
47 | size_t start = set.begin(); |
48 | for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical |
49 | Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment); |
50 | NodeRef node = bvh->encodeLeaf((char*)accel,items); |
51 | |
52 | LBBox3fa allBounds = empty; |
53 | for (size_t i=0; i<items; i++) |
54 | allBounds.extend(accel[i].fillMB(prims, start, set.end(), bvh->scene, time)); |
55 | |
56 | return NodeRecordMB(node,allBounds); |
57 | } |
58 | |
59 | BVH* bvh; |
60 | PrimRef* prims; |
61 | size_t time; |
62 | }; |
63 | #endif |
64 | |
65 | template<int N, typename Mesh, typename Primitive> |
66 | struct CreateMSMBlurLeaf |
67 | { |
68 | typedef BVHN<N> BVH; |
69 | typedef typename BVH::NodeRef NodeRef; |
70 | typedef typename BVH::NodeRecordMB4D NodeRecordMB4D; |
71 | |
72 | __forceinline CreateMSMBlurLeaf (BVH* bvh) : bvh(bvh) {} |
73 | |
74 | __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const |
75 | { |
76 | size_t items = Primitive::blocks(current.prims.size()); |
77 | size_t start = current.prims.begin(); |
78 | size_t end = current.prims.end(); |
79 | for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical |
80 | Primitive* accel = (Primitive*) alloc.malloc1(bytes: items*sizeof(Primitive),align: BVH::byteNodeAlignment); |
81 | NodeRef node = bvh->encodeLeaf((char*)accel,items); |
82 | LBBox3fa allBounds = empty; |
83 | for (size_t i=0; i<items; i++) |
84 | allBounds.extend(other: accel[i].fillMB(current.prims.prims->data(), start, current.prims.end(), bvh->scene, current.prims.time_range)); |
85 | return NodeRecordMB4D(node,allBounds,current.prims.time_range); |
86 | } |
87 | |
88 | BVH* bvh; |
89 | }; |
90 | |
91 | /* Motion blur BVH with 4D nodes and internal time splits */ |
92 | template<int N, typename Mesh, typename Primitive> |
93 | struct BVHNBuilderMBlurSAH : public Builder |
94 | { |
95 | typedef BVHN<N> BVH; |
96 | typedef typename BVHN<N>::NodeRef NodeRef; |
97 | typedef typename BVHN<N>::NodeRecordMB NodeRecordMB; |
98 | typedef typename BVHN<N>::AABBNodeMB AABBNodeMB; |
99 | |
100 | BVH* bvh; |
101 | Scene* scene; |
102 | const size_t sahBlockSize; |
103 | const float intCost; |
104 | const size_t minLeafSize; |
105 | const size_t maxLeafSize; |
106 | const Geometry::GTypeMask gtype_; |
107 | |
108 | BVHNBuilderMBlurSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype) |
109 | : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks)), gtype_(gtype) {} |
110 | |
111 | void build() |
112 | { |
113 | /* skip build for empty scene */ |
114 | const size_t numPrimitives = scene->getNumPrimitives(mask: gtype_,mblur: true); |
115 | if (numPrimitives == 0) { bvh->clear(); return; } |
116 | |
117 | double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(value: N) + "BuilderMBlurSAH" ); |
118 | |
119 | #if PROFILE |
120 | profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) { |
121 | #endif |
122 | |
123 | //const size_t numTimeSteps = scene->getNumTimeSteps<typename Mesh::type_t,true>(); |
124 | //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1); |
125 | |
126 | /*if (numTimeSegments == 1) |
127 | buildSingleSegment(numPrimitives); |
128 | else*/ |
129 | buildMultiSegment(numPrimitives); |
130 | |
131 | #if PROFILE |
132 | }); |
133 | #endif |
134 | |
135 | /* clear temporary data for static geometry */ |
136 | bvh->cleanup(); |
137 | bvh->postBuild(t0); |
138 | } |
139 | |
140 | #if 0 // No longer compatible when time_ranges are present for geometries. Would have to create temporal nodes sometimes, and put only a single geometry into leaf. |
141 | void buildSingleSegment(size_t numPrimitives) |
142 | { |
143 | /* create primref array */ |
144 | mvector<PrimRef> prims(scene->device,numPrimitives); |
145 | const PrimInfo pinfo = createPrimRefArrayMBlur(scene,gtype_,numPrimitives,prims,bvh->scene->progressInterface,0); |
146 | /* early out if no valid primitives */ |
147 | if (pinfo.size() == 0) { bvh->clear(); return; } |
148 | /* estimate acceleration structure size */ |
149 | const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N); |
150 | const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive)); |
151 | bvh->alloc.init_estimate(node_bytes+leaf_bytes); |
152 | |
153 | /* settings for BVH build */ |
154 | GeneralBVHBuilder::Settings settings; |
155 | settings.branchingFactor = N; |
156 | settings.maxDepth = BVH::maxBuildDepthLeaf; |
157 | settings.logBlockSize = bsr(sahBlockSize); |
158 | settings.minLeafSize = min(minLeafSize,maxLeafSize); |
159 | settings.maxLeafSize = maxLeafSize; |
160 | settings.travCost = travCost; |
161 | settings.intCost = intCost; |
162 | settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes); |
163 | |
164 | /* build hierarchy */ |
165 | auto root = BVHBuilderBinnedSAH::build<NodeRecordMB> |
166 | (typename BVH::CreateAlloc(bvh),typename BVH::AABBNodeMB::Create(),typename BVH::AABBNodeMB::Set(), |
167 | CreateMBlurLeaf<N,Primitive>(bvh,prims.data(),0),bvh->scene->progressInterface, |
168 | prims.data(),pinfo,settings); |
169 | |
170 | bvh->set(root.ref,root.lbounds,pinfo.size()); |
171 | } |
172 | #endif |
173 | |
174 | void buildMultiSegment(size_t numPrimitives) |
175 | { |
176 | /* create primref array */ |
177 | mvector<PrimRefMB> prims(scene->device,numPrimitives); |
178 | PrimInfoMB pinfo = createPrimRefArrayMSMBlur(scene,gtype_,numPrimitives,prims,bvh->scene->progressInterface); |
179 | |
180 | /* early out if no valid primitives */ |
181 | if (pinfo.size() == 0) { bvh->clear(); return; } |
182 | |
183 | /* estimate acceleration structure size */ |
184 | const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N); |
185 | const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(Primitive)); |
186 | bvh->alloc.init_estimate(node_bytes+leaf_bytes); |
187 | |
188 | /* settings for BVH build */ |
189 | BVHBuilderMSMBlur::Settings settings; |
190 | settings.branchingFactor = N; |
191 | settings.maxDepth = BVH::maxDepth; |
192 | settings.logBlockSize = bsr(v: sahBlockSize); |
193 | settings.minLeafSize = min(a: minLeafSize,b: maxLeafSize); |
194 | settings.maxLeafSize = maxLeafSize; |
195 | settings.travCost = travCost; |
196 | settings.intCost = intCost; |
197 | settings.singleLeafTimeSegment = Primitive::singleTimeSegment; |
198 | settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes); |
199 | |
200 | /* build hierarchy */ |
201 | auto root = |
202 | BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device, |
203 | RecalculatePrimRef<Mesh>(scene), |
204 | typename BVH::CreateAlloc(bvh), |
205 | typename BVH::AABBNodeMB4D::Create(), |
206 | typename BVH::AABBNodeMB4D::Set(), |
207 | CreateMSMBlurLeaf<N,Mesh,Primitive>(bvh), |
208 | bvh->scene->progressInterface, |
209 | settings); |
210 | |
211 | bvh->set(root.ref,root.lbounds,pinfo.num_time_segments); |
212 | } |
213 | |
214 | void clear() { |
215 | } |
216 | }; |
217 | |
218 | /************************************************************************************/ |
219 | /************************************************************************************/ |
220 | /************************************************************************************/ |
221 | /************************************************************************************/ |
222 | |
223 | struct GridRecalculatePrimRef |
224 | { |
225 | Scene* scene; |
226 | const SubGridBuildData * const sgrids; |
227 | |
228 | __forceinline GridRecalculatePrimRef (Scene* scene, const SubGridBuildData * const sgrids) |
229 | : scene(scene), sgrids(sgrids) {} |
230 | |
231 | __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const |
232 | { |
233 | const unsigned int geomID = prim.geomID(); |
234 | const GridMesh* mesh = scene->get<GridMesh>(i: geomID); |
235 | const unsigned int buildID = prim.primID(); |
236 | const SubGridBuildData &subgrid = sgrids[buildID]; |
237 | const unsigned int primID = subgrid.primID; |
238 | const size_t x = subgrid.x(); |
239 | const size_t y = subgrid.y(); |
240 | const LBBox3fa lbounds = mesh->linearBounds(g: mesh->grid(i: primID),sx: x,sy: y,dt: time_range); |
241 | const unsigned num_time_segments = mesh->numTimeSegments(); |
242 | const range<int> tbounds = mesh->timeSegmentRange(range: time_range); |
243 | return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, num_time_segments, geomID, buildID); |
244 | } |
245 | |
246 | __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const { |
247 | const unsigned int geomID = prim.geomID(); |
248 | const GridMesh* mesh = scene->get<GridMesh>(i: geomID); |
249 | const unsigned int buildID = prim.primID(); |
250 | const SubGridBuildData &subgrid = sgrids[buildID]; |
251 | const unsigned int primID = subgrid.primID; |
252 | const size_t x = subgrid.x(); |
253 | const size_t y = subgrid.y(); |
254 | return mesh->linearBounds(g: mesh->grid(i: primID),sx: x,sy: y,dt: time_range); |
255 | } |
256 | |
257 | }; |
258 | |
259 | template<int N> |
260 | struct CreateMSMBlurLeafGrid |
261 | { |
262 | typedef BVHN<N> BVH; |
263 | typedef typename BVH::NodeRef NodeRef; |
264 | typedef typename BVH::NodeRecordMB4D NodeRecordMB4D; |
265 | |
266 | __forceinline CreateMSMBlurLeafGrid (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids) : scene(scene), bvh(bvh), sgrids(sgrids) {} |
267 | |
268 | __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const |
269 | { |
270 | const size_t items = current.prims.size(); |
271 | const size_t start = current.prims.begin(); |
272 | |
273 | const PrimRefMB* prims = current.prims.prims->data(); |
274 | /* collect all subsets with unique geomIDs */ |
275 | assert(items <= N); |
276 | unsigned int geomIDs[N]; |
277 | unsigned int num_geomIDs = 1; |
278 | geomIDs[0] = prims[start].geomID(); |
279 | |
280 | for (size_t i=1;i<items;i++) |
281 | { |
282 | bool found = false; |
283 | const unsigned int new_geomID = prims[start+i].geomID(); |
284 | for (size_t j=0;j<num_geomIDs;j++) |
285 | if (new_geomID == geomIDs[j]) |
286 | { found = true; break; } |
287 | if (!found) |
288 | geomIDs[num_geomIDs++] = new_geomID; |
289 | } |
290 | |
291 | /* allocate all leaf memory in one single block */ |
292 | SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(bytes: num_geomIDs*sizeof(SubGridMBQBVHN<N>),align: BVH::byteAlignment); |
293 | typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs); |
294 | |
295 | LBBox3fa allBounds = empty; |
296 | |
297 | for (size_t g=0;g<num_geomIDs;g++) |
298 | { |
299 | const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]); |
300 | unsigned int x[N]; |
301 | unsigned int y[N]; |
302 | unsigned int primID[N]; |
303 | BBox3fa bounds0[N]; |
304 | BBox3fa bounds1[N]; |
305 | unsigned int pos = 0; |
306 | for (size_t i=0;i<items;i++) |
307 | { |
308 | if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue; |
309 | |
310 | const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()]; |
311 | x[pos] = sgrid_bd.sx; |
312 | y[pos] = sgrid_bd.sy; |
313 | primID[pos] = sgrid_bd.primID; |
314 | const size_t x = sgrid_bd.x(); |
315 | const size_t y = sgrid_bd.y(); |
316 | LBBox3fa newBounds = mesh->linearBounds(g: mesh->grid(i: sgrid_bd.primID),sx: x,sy: y,dt: current.prims.time_range); |
317 | allBounds.extend(other: newBounds); |
318 | bounds0[pos] = newBounds.bounds0; |
319 | bounds1[pos] = newBounds.bounds1; |
320 | pos++; |
321 | } |
322 | assert(pos <= N); |
323 | new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],current.prims.time_range.lower,1.0f/current.prims.time_range.size(),pos); |
324 | } |
325 | return NodeRecordMB4D(node,allBounds,current.prims.time_range); |
326 | } |
327 | |
328 | Scene *scene; |
329 | BVH* bvh; |
330 | const SubGridBuildData * const sgrids; |
331 | }; |
332 | |
333 | #if 0 |
334 | template<int N> |
335 | struct CreateLeafGridMB |
336 | { |
337 | typedef BVHN<N> BVH; |
338 | typedef typename BVH::NodeRef NodeRef; |
339 | typedef typename BVH::NodeRecordMB NodeRecordMB; |
340 | |
341 | __forceinline CreateLeafGridMB (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids) |
342 | : scene(scene), bvh(bvh), sgrids(sgrids) {} |
343 | |
344 | __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const |
345 | { |
346 | const size_t items = set.size(); |
347 | const size_t start = set.begin(); |
348 | |
349 | /* collect all subsets with unique geomIDs */ |
350 | assert(items <= N); |
351 | unsigned int geomIDs[N]; |
352 | unsigned int num_geomIDs = 1; |
353 | geomIDs[0] = prims[start].geomID(); |
354 | |
355 | for (size_t i=1;i<items;i++) |
356 | { |
357 | bool found = false; |
358 | const unsigned int new_geomID = prims[start+i].geomID(); |
359 | for (size_t j=0;j<num_geomIDs;j++) |
360 | if (new_geomID == geomIDs[j]) |
361 | { found = true; break; } |
362 | if (!found) |
363 | geomIDs[num_geomIDs++] = new_geomID; |
364 | } |
365 | |
366 | /* allocate all leaf memory in one single block */ |
367 | SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridMBQBVHN<N>),BVH::byteAlignment); |
368 | typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs); |
369 | |
370 | LBBox3fa allBounds = empty; |
371 | |
372 | for (size_t g=0;g<num_geomIDs;g++) |
373 | { |
374 | const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]); |
375 | |
376 | unsigned int x[N]; |
377 | unsigned int y[N]; |
378 | unsigned int primID[N]; |
379 | BBox3fa bounds0[N]; |
380 | BBox3fa bounds1[N]; |
381 | unsigned int pos = 0; |
382 | for (size_t i=0;i<items;i++) |
383 | { |
384 | if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue; |
385 | |
386 | const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()]; |
387 | x[pos] = sgrid_bd.sx; |
388 | y[pos] = sgrid_bd.sy; |
389 | primID[pos] = sgrid_bd.primID; |
390 | const size_t x = sgrid_bd.x(); |
391 | const size_t y = sgrid_bd.y(); |
392 | bool MAYBE_UNUSED valid0 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,0,bounds0[pos]); |
393 | bool MAYBE_UNUSED valid1 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,1,bounds1[pos]); |
394 | assert(valid0); |
395 | assert(valid1); |
396 | allBounds.extend(LBBox3fa(bounds0[pos],bounds1[pos])); |
397 | pos++; |
398 | } |
399 | new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],0.0f,1.0f,pos); |
400 | } |
401 | return NodeRecordMB(node,allBounds); |
402 | } |
403 | |
404 | Scene *scene; |
405 | BVH* bvh; |
406 | const SubGridBuildData * const sgrids; |
407 | }; |
408 | #endif |
409 | |
410 | |
411 | /* Motion blur BVH with 4D nodes and internal time splits */ |
412 | template<int N> |
413 | struct BVHNBuilderMBlurSAHGrid : public Builder |
414 | { |
415 | typedef BVHN<N> BVH; |
416 | typedef typename BVHN<N>::NodeRef NodeRef; |
417 | typedef typename BVHN<N>::NodeRecordMB NodeRecordMB; |
418 | typedef typename BVHN<N>::AABBNodeMB AABBNodeMB; |
419 | |
420 | BVH* bvh; |
421 | Scene* scene; |
422 | const size_t sahBlockSize; |
423 | const float intCost; |
424 | const size_t minLeafSize; |
425 | const size_t maxLeafSize; |
426 | mvector<SubGridBuildData> sgrids; |
427 | |
428 | |
429 | BVHNBuilderMBlurSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize) |
430 | : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,BVH::maxLeafBlocks)), sgrids(scene->device,0) {} |
431 | |
432 | |
433 | PrimInfo createPrimRefArrayMBlurGrid(Scene* scene, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime) |
434 | { |
435 | /* first run to get #primitives */ |
436 | ParallelForForPrefixSumState<PrimInfo> pstate; |
437 | Scene::Iterator<GridMesh,true> iter(scene); |
438 | |
439 | pstate.init(array2&: iter,minStepSize: size_t(1024)); |
440 | |
441 | /* iterate over all meshes in the scene */ |
442 | PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo { |
443 | |
444 | PrimInfo pinfo(empty); |
445 | for (size_t j=r.begin(); j<r.end(); j++) |
446 | { |
447 | if (!mesh->valid(gridID: j,itime_range: range<size_t>(0,1))) continue; |
448 | BBox3fa bounds = empty; |
449 | const PrimRef prim(bounds,unsigned(geomID),unsigned(j)); |
450 | pinfo.add_center2(prim,i: mesh->getNumSubGrids(gridID: j)); |
451 | } |
452 | return pinfo; |
453 | }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); |
454 | |
455 | size_t numPrimitives = pinfo.size(); |
456 | if (numPrimitives == 0) return pinfo; |
457 | |
458 | /* resize arrays */ |
459 | sgrids.resize(new_size: numPrimitives); |
460 | prims.resize(new_size: numPrimitives); |
461 | |
462 | /* second run to fill primrefs and SubGridBuildData arrays */ |
463 | pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo { |
464 | |
465 | k = base.size(); |
466 | size_t p_index = k; |
467 | PrimInfo pinfo(empty); |
468 | for (size_t j=r.begin(); j<r.end(); j++) |
469 | { |
470 | const GridMesh::Grid &g = mesh->grid(i: j); |
471 | if (!mesh->valid(gridID: j,itime_range: range<size_t>(0,1))) continue; |
472 | |
473 | for (unsigned int y=0; y<g.resY-1u; y+=2) |
474 | for (unsigned int x=0; x<g.resX-1u; x+=2) |
475 | { |
476 | BBox3fa bounds = empty; |
477 | if (!mesh->buildBounds(g,sx: x,sy: y,itime,bbox&: bounds)) continue; // get bounds of subgrid |
478 | const PrimRef prim(bounds,unsigned(geomID),unsigned(p_index)); |
479 | pinfo.add_center2(prim); |
480 | sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); |
481 | prims[p_index++] = prim; |
482 | } |
483 | } |
484 | return pinfo; |
485 | }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); |
486 | |
487 | assert(pinfo.size() == numPrimitives); |
488 | return pinfo; |
489 | } |
490 | |
491 | PrimInfoMB createPrimRefArrayMSMBlurGrid(Scene* scene, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f)) |
492 | { |
493 | /* first run to get #primitives */ |
494 | ParallelForForPrefixSumState<PrimInfoMB> pstate; |
495 | Scene::Iterator<GridMesh,true> iter(scene); |
496 | |
497 | pstate.init(array2&: iter,minStepSize: size_t(1024)); |
498 | /* iterate over all meshes in the scene */ |
499 | PrimInfoMB pinfoMB = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t /*geomID*/) -> PrimInfoMB { |
500 | |
501 | PrimInfoMB pinfoMB(empty); |
502 | for (size_t j=r.begin(); j<r.end(); j++) |
503 | { |
504 | if (!mesh->valid(gridID: j, itime_range: mesh->timeSegmentRange(range: t0t1))) continue; |
505 | LBBox3fa bounds(empty); |
506 | PrimInfoMB gridMB(0,mesh->getNumSubGrids(gridID: j)); |
507 | pinfoMB.merge(other: gridMB); |
508 | } |
509 | return pinfoMB; |
510 | }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); |
511 | |
512 | size_t numPrimitives = pinfoMB.size(); |
513 | if (numPrimitives == 0) return pinfoMB; |
514 | |
515 | /* resize arrays */ |
516 | sgrids.resize(new_size: numPrimitives); |
517 | prims.resize(new_size: numPrimitives); |
518 | /* second run to fill primrefs and SubGridBuildData arrays */ |
519 | pinfoMB = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB { |
520 | |
521 | k = base.size(); |
522 | size_t p_index = k; |
523 | PrimInfoMB pinfoMB(empty); |
524 | for (size_t j=r.begin(); j<r.end(); j++) |
525 | { |
526 | if (!mesh->valid(gridID: j, itime_range: mesh->timeSegmentRange(range: t0t1))) continue; |
527 | const GridMesh::Grid &g = mesh->grid(i: j); |
528 | |
529 | for (unsigned int y=0; y<g.resY-1u; y+=2) |
530 | for (unsigned int x=0; x<g.resX-1u; x+=2) |
531 | { |
532 | const PrimRefMB prim(mesh->linearBounds(g,sx: x,sy: y,dt: t0t1),mesh->numTimeSegments(),mesh->time_range,mesh->numTimeSegments(),unsigned(geomID),unsigned(p_index)); |
533 | pinfoMB.add_primref(prim); |
534 | sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); |
535 | prims[p_index++] = prim; |
536 | } |
537 | } |
538 | return pinfoMB; |
539 | }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); |
540 | |
541 | assert(pinfoMB.size() == numPrimitives); |
542 | pinfoMB.time_range = t0t1; |
543 | return pinfoMB; |
544 | } |
545 | |
546 | void build() |
547 | { |
548 | /* skip build for empty scene */ |
549 | const size_t numPrimitives = scene->getNumPrimitives(mask: GridMesh::geom_type,mblur: true); |
550 | if (numPrimitives == 0) { bvh->clear(); return; } |
551 | |
552 | double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(value: N) + "BuilderMBlurSAHGrid" ); |
553 | |
554 | //const size_t numTimeSteps = scene->getNumTimeSteps<GridMesh,true>(); |
555 | //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1); |
556 | //if (numTimeSegments == 1) |
557 | // buildSingleSegment(numPrimitives); |
558 | //else |
559 | buildMultiSegment(numPrimitives); |
560 | |
561 | /* clear temporary data for static geometry */ |
562 | bvh->cleanup(); |
563 | bvh->postBuild(t0); |
564 | } |
565 | |
566 | #if 0 |
567 | void buildSingleSegment(size_t numPrimitives) |
568 | { |
569 | /* create primref array */ |
570 | mvector<PrimRef> prims(scene->device,numPrimitives); |
571 | const PrimInfo pinfo = createPrimRefArrayMBlurGrid(scene,prims,bvh->scene->progressInterface,0); |
572 | /* early out if no valid primitives */ |
573 | if (pinfo.size() == 0) { bvh->clear(); return; } |
574 | |
575 | /* estimate acceleration structure size */ |
576 | const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N); |
577 | //TODO: check leaf_bytes |
578 | const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>)); |
579 | bvh->alloc.init_estimate(node_bytes+leaf_bytes); |
580 | |
581 | /* settings for BVH build */ |
582 | GeneralBVHBuilder::Settings settings; |
583 | settings.branchingFactor = N; |
584 | settings.maxDepth = BVH::maxBuildDepthLeaf; |
585 | settings.logBlockSize = bsr(sahBlockSize); |
586 | settings.minLeafSize = min(minLeafSize,maxLeafSize); |
587 | settings.maxLeafSize = maxLeafSize; |
588 | settings.travCost = travCost; |
589 | settings.intCost = intCost; |
590 | settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes); |
591 | |
592 | /* build hierarchy */ |
593 | auto root = BVHBuilderBinnedSAH::build<NodeRecordMB> |
594 | (typename BVH::CreateAlloc(bvh), |
595 | typename BVH::AABBNodeMB::Create(), |
596 | typename BVH::AABBNodeMB::Set(), |
597 | CreateLeafGridMB<N>(scene,bvh,sgrids.data()), |
598 | bvh->scene->progressInterface, |
599 | prims.data(),pinfo,settings); |
600 | |
601 | bvh->set(root.ref,root.lbounds,pinfo.size()); |
602 | } |
603 | #endif |
604 | |
605 | void buildMultiSegment(size_t numPrimitives) |
606 | { |
607 | /* create primref array */ |
608 | mvector<PrimRefMB> prims(scene->device,numPrimitives); |
609 | PrimInfoMB pinfo = createPrimRefArrayMSMBlurGrid(scene,prims,progressMonitor&: bvh->scene->progressInterface); |
610 | |
611 | /* early out if no valid primitives */ |
612 | if (pinfo.size() == 0) { bvh->clear(); return; } |
613 | |
614 | |
615 | |
616 | GridRecalculatePrimRef recalculatePrimRef(scene,sgrids.data()); |
617 | |
618 | /* estimate acceleration structure size */ |
619 | const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N); |
620 | //FIXME: check leaf_bytes |
621 | //const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(SubGridQBVHN<N>)); |
622 | const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>)); |
623 | |
624 | bvh->alloc.init_estimate(node_bytes+leaf_bytes); |
625 | |
626 | /* settings for BVH build */ |
627 | BVHBuilderMSMBlur::Settings settings; |
628 | settings.branchingFactor = N; |
629 | settings.maxDepth = BVH::maxDepth; |
630 | settings.logBlockSize = bsr(v: sahBlockSize); |
631 | settings.minLeafSize = min(a: minLeafSize,b: maxLeafSize); |
632 | settings.maxLeafSize = maxLeafSize; |
633 | settings.travCost = travCost; |
634 | settings.intCost = intCost; |
635 | settings.singleLeafTimeSegment = false; |
636 | settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes); |
637 | |
638 | /* build hierarchy */ |
639 | auto root = |
640 | BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device, |
641 | recalculatePrimRef, |
642 | typename BVH::CreateAlloc(bvh), |
643 | typename BVH::AABBNodeMB4D::Create(), |
644 | typename BVH::AABBNodeMB4D::Set(), |
645 | CreateMSMBlurLeafGrid<N>(scene,bvh,sgrids.data()), |
646 | bvh->scene->progressInterface, |
647 | settings); |
648 | bvh->set(root.ref,root.lbounds,pinfo.num_time_segments); |
649 | } |
650 | |
651 | void clear() { |
652 | } |
653 | }; |
654 | |
655 | /************************************************************************************/ |
656 | /************************************************************************************/ |
657 | /************************************************************************************/ |
658 | /************************************************************************************/ |
659 | |
660 | #if defined(EMBREE_GEOMETRY_TRIANGLE) |
661 | Builder* BVH4Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); } |
662 | Builder* BVH4Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4vMB>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); } |
663 | #if defined(__AVX__) |
664 | Builder* BVH8Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); } |
665 | Builder* BVH8Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4vMB>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); } |
666 | #endif |
667 | #endif |
668 | |
669 | #if defined(EMBREE_GEOMETRY_QUAD) |
670 | Builder* BVH4Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,QuadMesh,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); } |
671 | #if defined(__AVX__) |
672 | Builder* BVH8Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,QuadMesh,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); } |
673 | #endif |
674 | #endif |
675 | |
676 | #if defined(EMBREE_GEOMETRY_USER) |
677 | Builder* BVH4VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { |
678 | int minLeafSize = scene->device->object_accel_mb_min_leaf_size; |
679 | int maxLeafSize = scene->device->object_accel_mb_max_leaf_size; |
680 | return new BVHNBuilderMBlurSAH<4,UserGeometry,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY); |
681 | } |
682 | #if defined(__AVX__) |
683 | Builder* BVH8VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { |
684 | int minLeafSize = scene->device->object_accel_mb_min_leaf_size; |
685 | int maxLeafSize = scene->device->object_accel_mb_max_leaf_size; |
686 | return new BVHNBuilderMBlurSAH<8,UserGeometry,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY); |
687 | } |
688 | #endif |
689 | #endif |
690 | |
691 | #if defined(EMBREE_GEOMETRY_INSTANCE) |
692 | Builder* BVH4InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); } |
693 | #if defined(__AVX__) |
694 | Builder* BVH8InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); } |
695 | #endif |
696 | #endif |
697 | |
698 | #if defined(EMBREE_GEOMETRY_GRID) |
699 | Builder* BVH4GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4); } |
700 | #if defined(__AVX__) |
701 | Builder* BVH8GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8); } |
702 | #endif |
703 | #endif |
704 | } |
705 | } |
706 | |