1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #include "bvh_builder_twolevel.h" |
5 | #include "bvh_statistics.h" |
6 | #include "../builders/bvh_builder_sah.h" |
7 | #include "../common/scene_line_segments.h" |
8 | #include "../common/scene_triangle_mesh.h" |
9 | #include "../common/scene_quad_mesh.h" |
10 | |
11 | #define PROFILE 0 |
12 | |
13 | namespace embree |
14 | { |
15 | namespace isa |
16 | { |
17 | template<int N, typename Mesh, typename Primitive> |
18 | BVHNBuilderTwoLevel<N,Mesh,Primitive>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder, const size_t singleThreadThreshold) |
19 | : bvh(bvh), scene(scene), refs(scene->device,0), prims(scene->device,0), singleThreadThreshold(singleThreadThreshold), gtype(gtype), useMortonBuilder_(useMortonBuilder) {} |
20 | |
21 | template<int N, typename Mesh, typename Primitive> |
22 | BVHNBuilderTwoLevel<N,Mesh,Primitive>::~BVHNBuilderTwoLevel () { |
23 | } |
24 | |
25 | // =========================================================================== |
26 | // =========================================================================== |
27 | // =========================================================================== |
28 | |
29 | template<int N, typename Mesh, typename Primitive> |
30 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::build() |
31 | { |
32 | /* delete some objects */ |
33 | size_t num = scene->size(); |
34 | if (num < bvh->objects.size()) { |
35 | parallel_for(num, bvh->objects.size(), [&] (const range<size_t>& r) { |
36 | for (size_t i=r.begin(); i<r.end(); i++) { |
37 | builders[i].reset(); |
38 | delete bvh->objects[i]; bvh->objects[i] = nullptr; |
39 | } |
40 | }); |
41 | } |
42 | |
43 | #if PROFILE |
44 | while(1) |
45 | #endif |
46 | { |
47 | /* reset memory allocator */ |
48 | bvh->alloc.reset(); |
49 | |
50 | /* skip build for empty scene */ |
51 | const size_t numPrimitives = scene->getNumPrimitives(mask: gtype,mblur: false); |
52 | |
53 | if (numPrimitives == 0) { |
54 | prims.resize(new_size: 0); |
55 | bvh->set(BVH::emptyNode,empty,0); |
56 | return; |
57 | } |
58 | |
59 | /* calculate the size of the entire BVH */ |
60 | const size_t numLeafBlocks = Primitive::blocks(numPrimitives); |
61 | const size_t node_bytes = 2*numLeafBlocks*sizeof(typename BVH::AABBNode)/N; |
62 | const size_t leaf_bytes = size_t(1.2*numLeafBlocks*sizeof(Primitive)); |
63 | bvh->alloc.init_estimate(node_bytes+leaf_bytes); |
64 | |
65 | double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(value: N) + "BuilderTwoLevel" ); |
66 | |
67 | /* resize object array if scene got larger */ |
68 | if (bvh->objects.size() < num) bvh->objects.resize(num); |
69 | if (builders.size() < num) builders.resize(num); |
70 | resizeRefsList (); |
71 | nextRef.store(i: 0); |
72 | |
73 | /* create acceleration structures */ |
74 | parallel_for(size_t(0), num, [&] (const range<size_t>& r) |
75 | { |
76 | for (size_t objectID=r.begin(); objectID<r.end(); objectID++) |
77 | { |
78 | Mesh* mesh = scene->getSafe<Mesh>(objectID); |
79 | |
80 | /* ignore meshes we do not support */ |
81 | if (mesh == nullptr || mesh->numTimeSteps != 1) |
82 | continue; |
83 | |
84 | if (isSmallGeometry(mesh)) { |
85 | setupSmallBuildRefBuilder (objectID, mesh); |
86 | } else { |
87 | setupLargeBuildRefBuilder (objectID, mesh); |
88 | } |
89 | } |
90 | }); |
91 | |
92 | /* parallel build of acceleration structures */ |
93 | parallel_for(size_t(0), num, [&] (const range<size_t>& r) |
94 | { |
95 | for (size_t objectID=r.begin(); objectID<r.end(); objectID++) |
96 | { |
97 | /* ignore if no triangle mesh or not enabled */ |
98 | Mesh* mesh = scene->getSafe<Mesh>(objectID); |
99 | if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1) |
100 | continue; |
101 | |
102 | builders[objectID]->attachBuildRefs (this); |
103 | } |
104 | }); |
105 | |
106 | |
107 | #if PROFILE |
108 | double d0 = getSeconds(); |
109 | #endif |
110 | /* fast path for single geometry scenes */ |
111 | if (nextRef == 1) { |
112 | bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives); |
113 | } |
114 | |
115 | else |
116 | { |
117 | /* open all large nodes */ |
118 | refs.resize(nextRef); |
119 | |
120 | /* this probably needs some more tuning */ |
121 | const size_t extSize = max(max((size_t)SPLIT_MIN_EXT_SPACE,refs.size()*SPLIT_MEMORY_RESERVE_SCALE),size_t((float)numPrimitives / SPLIT_MEMORY_RESERVE_FACTOR)); |
122 | |
123 | #if !ENABLE_DIRECT_SAH_MERGE_BUILDER |
124 | |
125 | #if ENABLE_OPEN_SEQUENTIAL |
126 | open_sequential(extSize); |
127 | #endif |
128 | /* compute PrimRefs */ |
129 | prims.resize(refs.size()); |
130 | #endif |
131 | |
132 | { |
133 | #if ENABLE_DIRECT_SAH_MERGE_BUILDER |
134 | |
135 | const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo { |
136 | |
137 | PrimInfo pinfo(empty); |
138 | for (size_t i=r.begin(); i<r.end(); i++) { |
139 | pinfo.add_center2(refs[i]); |
140 | } |
141 | return pinfo; |
142 | }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); }); |
143 | |
144 | #else |
145 | const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo { |
146 | |
147 | PrimInfo pinfo(empty); |
148 | for (size_t i=r.begin(); i<r.end(); i++) { |
149 | pinfo.add_center2(refs[i]); |
150 | prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node); |
151 | } |
152 | return pinfo; |
153 | }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); }); |
154 | #endif |
155 | |
156 | /* skip if all objects where empty */ |
157 | if (pinfo.size() == 0) |
158 | bvh->set(BVH::emptyNode,empty,0); |
159 | |
160 | /* otherwise build toplevel hierarchy */ |
161 | else |
162 | { |
163 | /* settings for BVH build */ |
164 | GeneralBVHBuilder::Settings settings; |
165 | settings.branchingFactor = N; |
166 | settings.maxDepth = BVH::maxBuildDepthLeaf; |
167 | settings.logBlockSize = bsr(v: N); |
168 | settings.minLeafSize = 1; |
169 | settings.maxLeafSize = 1; |
170 | settings.travCost = 1.0f; |
171 | settings.intCost = 1.0f; |
172 | settings.singleThreadThreshold = singleThreadThreshold; |
173 | |
174 | #if ENABLE_DIRECT_SAH_MERGE_BUILDER |
175 | |
176 | refs.resize(extSize); |
177 | |
178 | NodeRef root = BVHBuilderBinnedOpenMergeSAH::build<NodeRef,BuildRef>( |
179 | typename BVH::CreateAlloc(bvh), |
180 | typename BVH::AABBNode::Create2(), |
181 | typename BVH::AABBNode::Set2(), |
182 | |
183 | [&] (const BuildRef* refs, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef { |
184 | assert(range.size() == 1); |
185 | return (NodeRef) refs[range.begin()].node; |
186 | }, |
187 | [&] (BuildRef &bref, BuildRef *refs) -> size_t { |
188 | return openBuildRef(bref,refs); |
189 | }, |
190 | [&] (size_t dn) { bvh->scene->progressMonitor(0); }, |
191 | refs.data(),extSize,pinfo,settings); |
192 | #else |
193 | NodeRef root = BVHBuilderBinnedSAH::build<NodeRef>( |
194 | typename BVH::CreateAlloc(bvh), |
195 | typename BVH::AABBNode::Create2(), |
196 | typename BVH::AABBNode::Set2(), |
197 | |
198 | [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef { |
199 | assert(range.size() == 1); |
200 | return (NodeRef) prims[range.begin()].ID(); |
201 | }, |
202 | [&] (size_t dn) { bvh->scene->progressMonitor(0); }, |
203 | prims.data(),pinfo,settings); |
204 | #endif |
205 | |
206 | |
207 | bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives); |
208 | } |
209 | } |
210 | } |
211 | |
212 | bvh->alloc.cleanup(); |
213 | bvh->postBuild(t0); |
214 | #if PROFILE |
215 | double d1 = getSeconds(); |
216 | std::cout << "TOP_LEVEL OPENING/REBUILD TIME " << 1000.0*(d1-d0) << " ms" << std::endl; |
217 | #endif |
218 | } |
219 | |
220 | } |
221 | |
222 | template<int N, typename Mesh, typename Primitive> |
223 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::deleteGeometry(size_t geomID) |
224 | { |
225 | if (geomID >= bvh->objects.size()) return; |
226 | if (builders[geomID]) builders[geomID].reset(); |
227 | delete bvh->objects [geomID]; bvh->objects [geomID] = nullptr; |
228 | } |
229 | |
230 | template<int N, typename Mesh, typename Primitive> |
231 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::clear() |
232 | { |
233 | for (size_t i=0; i<bvh->objects.size(); i++) |
234 | if (bvh->objects[i]) bvh->objects[i]->clear(); |
235 | |
236 | for (size_t i=0; i<builders.size(); i++) |
237 | if (builders[i]) builders[i].reset(); |
238 | |
239 | refs.clear(); |
240 | } |
241 | |
242 | template<int N, typename Mesh, typename Primitive> |
243 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::open_sequential(const size_t extSize) |
244 | { |
245 | if (refs.size() == 0) |
246 | return; |
247 | |
248 | refs.reserve(extSize); |
249 | |
250 | #if 1 |
251 | for (size_t i=0;i<refs.size();i++) |
252 | { |
253 | NodeRef ref = refs[i].node; |
254 | if (ref.isAABBNode()) |
255 | BVH::prefetch(ref); |
256 | } |
257 | #endif |
258 | |
259 | std::make_heap(refs.begin(),refs.end()); |
260 | while (refs.size()+N-1 <= extSize) |
261 | { |
262 | std::pop_heap (refs.begin(),refs.end()); |
263 | NodeRef ref = refs.back().node; |
264 | if (ref.isLeaf()) break; |
265 | refs.pop_back(); |
266 | |
267 | AABBNode* node = ref.getAABBNode(); |
268 | for (size_t i=0; i<N; i++) { |
269 | if (node->child(i) == BVH::emptyNode) continue; |
270 | refs.push_back(BuildRef(node->bounds(i),node->child(i))); |
271 | |
272 | #if 1 |
273 | NodeRef ref_pre = node->child(i); |
274 | if (ref_pre.isAABBNode()) |
275 | ref_pre.prefetch(); |
276 | #endif |
277 | std::push_heap (refs.begin(),refs.end()); |
278 | } |
279 | } |
280 | } |
281 | |
282 | template<int N, typename Mesh, typename Primitive> |
283 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupSmallBuildRefBuilder (size_t objectID, Mesh const * const /*mesh*/) |
284 | { |
285 | if (builders[objectID] == nullptr || // new mesh |
286 | dynamic_cast<RefBuilderSmall*>(builders[objectID].get()) == nullptr) // size change resulted in large->small change |
287 | { |
288 | builders[objectID].reset (new RefBuilderSmall(objectID)); |
289 | } |
290 | } |
291 | |
292 | template<int N, typename Mesh, typename Primitive> |
293 | void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh) |
294 | { |
295 | if (bvh->objects[objectID] == nullptr || // new mesh |
296 | builders[objectID]->meshQualityChanged (mesh->quality) || // changed build quality |
297 | dynamic_cast<RefBuilderLarge*>(builders[objectID].get()) == nullptr) // size change resulted in small->large change |
298 | { |
299 | Builder* builder = nullptr; |
300 | delete bvh->objects[objectID]; |
301 | createMeshAccel(geomID: objectID, builder); |
302 | builders[objectID].reset (new RefBuilderLarge(objectID, builder, mesh->quality)); |
303 | } |
304 | } |
305 | |
306 | #if defined(EMBREE_GEOMETRY_TRIANGLE) |
307 | Builder* BVH4BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
308 | return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
309 | } |
310 | Builder* BVH4BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
311 | return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4v>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
312 | } |
313 | Builder* BVH4BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
314 | return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
315 | } |
316 | #endif |
317 | |
318 | #if defined(EMBREE_GEOMETRY_QUAD) |
319 | Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
320 | return new BVHNBuilderTwoLevel<4,QuadMesh,Quad4v>((BVH4*)bvh,scene,QuadMesh::geom_type,useMortonBuilder); |
321 | } |
322 | #endif |
323 | |
324 | #if defined(EMBREE_GEOMETRY_USER) |
325 | Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
326 | return new BVHNBuilderTwoLevel<4,UserGeometry,Object>((BVH4*)bvh,scene,UserGeometry::geom_type,useMortonBuilder); |
327 | } |
328 | #endif |
329 | |
330 | #if defined(EMBREE_GEOMETRY_INSTANCE) |
331 | Builder* BVH4BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) { |
332 | return new BVHNBuilderTwoLevel<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder); |
333 | } |
334 | #endif |
335 | |
336 | #if defined(__AVX__) |
337 | #if defined(EMBREE_GEOMETRY_TRIANGLE) |
338 | Builder* BVH8BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
339 | return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
340 | } |
341 | Builder* BVH8BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
342 | return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4v>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
343 | } |
344 | Builder* BVH8BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
345 | return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder); |
346 | } |
347 | #endif |
348 | |
349 | #if defined(EMBREE_GEOMETRY_QUAD) |
350 | Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
351 | return new BVHNBuilderTwoLevel<8,QuadMesh,Quad4v>((BVH8*)bvh,scene,QuadMesh::geom_type,useMortonBuilder); |
352 | } |
353 | #endif |
354 | |
355 | #if defined(EMBREE_GEOMETRY_USER) |
356 | Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) { |
357 | return new BVHNBuilderTwoLevel<8,UserGeometry,Object>((BVH8*)bvh,scene,UserGeometry::geom_type,useMortonBuilder); |
358 | } |
359 | #endif |
360 | |
361 | #if defined(EMBREE_GEOMETRY_INSTANCE) |
362 | Builder* BVH8BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) { |
363 | return new BVHNBuilderTwoLevel<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder); |
364 | } |
365 | #endif |
366 | |
367 | #endif |
368 | } |
369 | } |
370 | |