Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h
9906 views
1
// Copyright 2009-2021 Intel Corporation
2
// SPDX-License-Identifier: Apache-2.0
3
4
#pragma once
5
6
#include <type_traits>
7
8
#include "bvh_builder_twolevel_internal.h"
9
#include "bvh.h"
10
#include "../builders/priminfo.h"
11
#include "../builders/primrefgen.h"
12
13
/* new open/merge builder */
14
#define ENABLE_DIRECT_SAH_MERGE_BUILDER 1
15
#define ENABLE_OPEN_SEQUENTIAL 0
16
#define SPLIT_MEMORY_RESERVE_FACTOR 1000
17
#define SPLIT_MEMORY_RESERVE_SCALE 2
18
#define SPLIT_MIN_EXT_SPACE 1000
19
20
namespace embree
21
{
22
namespace isa
23
{
24
template<int N, typename Mesh, typename Primitive>
25
class BVHNBuilderTwoLevel : public Builder
26
{
27
typedef BVHN<N> BVH;
28
typedef typename BVH::AABBNode AABBNode;
29
typedef typename BVH::NodeRef NodeRef;
30
31
__forceinline static bool isSmallGeometry(Mesh* mesh) {
32
return mesh->size() <= 4;
33
}
34
35
public:
36
37
typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
38
39
struct BuildRef : public PrimRef
40
{
41
public:
42
__forceinline BuildRef () {}
43
44
__forceinline BuildRef (const BBox3fa& bounds, NodeRef node)
45
: PrimRef(bounds,(size_t)node), node(node)
46
{
47
if (node.isLeaf())
48
bounds_area = 0.0f;
49
else
50
bounds_area = area(this->bounds());
51
}
52
53
/* used by the open/merge bvh builder */
54
__forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)
55
: PrimRef(bounds,geomID,numPrimitives), node(node)
56
{
57
/* important for relative buildref ordering */
58
if (node.isLeaf())
59
bounds_area = 0.0f;
60
else
61
bounds_area = area(this->bounds());
62
}
63
64
__forceinline size_t size() const {
65
return primID();
66
}
67
68
friend bool operator< (const BuildRef& a, const BuildRef& b) {
69
return a.bounds_area < b.bounds_area;
70
}
71
72
friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {
73
return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";
74
}
75
76
__forceinline unsigned int numPrimitives() const { return primID(); }
77
78
public:
79
NodeRef node;
80
float bounds_area;
81
};
82
83
84
__forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {
85
if (bref.node.isLeaf())
86
{
87
refs[0] = bref;
88
return 1;
89
}
90
NodeRef ref = bref.node;
91
unsigned int geomID = bref.geomID();
92
unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);
93
AABBNode* node = ref.getAABBNode();
94
size_t n = 0;
95
for (size_t i=0; i<N; i++) {
96
if (node->child(i) == BVH::emptyNode) continue;
97
refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);
98
n++;
99
}
100
assert(n > 1);
101
return n;
102
}
103
104
/*! Constructor. */
105
BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);
106
107
/*! Destructor */
108
~BVHNBuilderTwoLevel ();
109
110
/*! builder entry point */
111
void build();
112
void deleteGeometry(size_t geomID);
113
void clear();
114
115
void open_sequential(const size_t extSize);
116
117
private:
118
119
class RefBuilderBase {
120
public:
121
virtual ~RefBuilderBase () {}
122
virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;
123
virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;
124
};
125
126
class RefBuilderSmall : public RefBuilderBase {
127
public:
128
129
RefBuilderSmall (size_t objectID)
130
: objectID_ (objectID) {}
131
132
void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {
133
134
Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);
135
size_t meshSize = mesh->size();
136
assert(isSmallGeometry(mesh));
137
138
mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);
139
auto pinfo = createPrimRefArray(mesh,objectID_,meshSize,prefs,topBuilder->bvh->scene->progressInterface);
140
141
size_t begin=0;
142
while (begin < pinfo.size())
143
{
144
Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);
145
typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);
146
accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);
147
148
/* create build primitive */
149
#if ENABLE_DIRECT_SAH_MERGE_BUILDER
150
topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);
151
#else
152
topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);
153
#endif
154
}
155
assert(begin == pinfo.size());
156
}
157
158
bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {
159
return false;
160
}
161
162
size_t objectID_;
163
};
164
165
class RefBuilderLarge : public RefBuilderBase {
166
public:
167
168
RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)
169
: objectID_ (objectID), builder_ (builder), quality_ (quality) {}
170
171
void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)
172
{
173
BVH* object = topBuilder->getBVH(objectID_); assert(object);
174
175
/* build object if it got modified */
176
if (topBuilder->isGeometryModified(objectID_))
177
builder_->build();
178
179
/* create build primitive */
180
if (!object->getBounds().empty())
181
{
182
#if ENABLE_DIRECT_SAH_MERGE_BUILDER
183
Mesh* mesh = topBuilder->getMesh(objectID_);
184
topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());
185
#else
186
topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
187
#endif
188
}
189
}
190
191
bool meshQualityChanged (RTCBuildQuality currQuality) {
192
return currQuality != quality_;
193
}
194
195
private:
196
size_t objectID_;
197
Ref<Builder> builder_;
198
RTCBuildQuality quality_;
199
};
200
201
void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);
202
void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);
203
204
BVH* getBVH (size_t objectID) {
205
return this->bvh->objects[objectID];
206
}
207
Mesh* getMesh (size_t objectID) {
208
return this->scene->template getSafe<Mesh>(objectID);
209
}
210
bool isGeometryModified (size_t objectID) {
211
return this->scene->isGeometryModified(objectID);
212
}
213
214
void resizeRefsList ()
215
{
216
size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0),
217
[this](const range<size_t>& r)->size_t {
218
size_t c = 0;
219
for (auto i=r.begin(); i<r.end(); ++i) {
220
Mesh* mesh = scene->getSafe<Mesh>(i);
221
if (mesh == nullptr || mesh->numTimeSteps != 1)
222
continue;
223
size_t meshSize = mesh->size();
224
c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;
225
}
226
return c;
227
},
228
std::plus<size_t>()
229
);
230
231
if (refs.size() < num) {
232
refs.resize(num);
233
}
234
}
235
236
void createMeshAccel (size_t geomID, Builder*& builder)
237
{
238
bvh->objects[geomID] = new BVH(Primitive::type,scene);
239
BVH* accel = bvh->objects[geomID];
240
auto mesh = scene->getSafe<Mesh>(geomID);
241
if (nullptr == mesh) {
242
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");
243
return;
244
}
245
246
__internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);
247
}
248
249
using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;
250
251
BuilderList builders;
252
BVH* bvh;
253
Scene* scene;
254
mvector<BuildRef> refs;
255
mvector<PrimRef> prims;
256
std::atomic<int> nextRef;
257
const size_t singleThreadThreshold;
258
Geometry::GTypeMask gtype;
259
bool useMortonBuilder_ = false;
260
};
261
}
262
}
263
264