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