Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/builders/heuristic_binning_array_unaligned.h
9906 views
1
// Copyright 2009-2021 Intel Corporation
2
// SPDX-License-Identifier: Apache-2.0
3
4
#pragma once
5
6
#include "heuristic_binning.h"
7
8
namespace embree
9
{
10
namespace isa
11
{
12
/*! Performs standard object binning */
13
template<typename PrimRef, size_t BINS>
14
struct UnalignedHeuristicArrayBinningSAH
15
{
16
typedef BinSplit<BINS> Split;
17
typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
18
typedef range<size_t> Set;
19
20
__forceinline UnalignedHeuristicArrayBinningSAH () // FIXME: required?
21
: scene(nullptr), prims(nullptr) {}
22
23
/*! remember prim array */
24
__forceinline UnalignedHeuristicArrayBinningSAH (Scene* scene, PrimRef* prims)
25
: scene(scene), prims(prims) {}
26
27
const LinearSpace3fa computeAlignedSpace(const range<size_t>& set)
28
{
29
Vec3fa axis(0,0,1);
30
uint64_t bestGeomPrimID = -1;
31
32
/*! find curve with minimum ID that defines valid direction */
33
for (size_t i=set.begin(); i<set.end(); i++)
34
{
35
const unsigned int geomID = prims[i].geomID();
36
const unsigned int primID = prims[i].primID();
37
const uint64_t geomprimID = prims[i].ID64();
38
if (geomprimID >= bestGeomPrimID) continue;
39
const Vec3fa axis1 = scene->get(geomID)->computeDirection(primID);
40
if (sqr_length(axis1) > 1E-18f) {
41
axis = normalize(axis1);
42
bestGeomPrimID = geomprimID;
43
}
44
}
45
return frame(axis).transposed();
46
}
47
48
const PrimInfo computePrimInfo(const range<size_t>& set, const LinearSpace3fa& space)
49
{
50
auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
51
{
52
CentGeomBBox3fa bounds(empty);
53
for (size_t i=r.begin(); i<r.end(); i++) {
54
Geometry* mesh = scene->get(prims[i].geomID());
55
bounds.extend(mesh->vbounds(space,prims[i].primID()));
56
}
57
return bounds;
58
};
59
60
const CentGeomBBox3fa bounds = parallel_reduce(set.begin(), set.end(), size_t(1024), size_t(4096),
61
CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
62
63
return PrimInfo(set.begin(),set.end(),bounds);
64
}
65
66
struct BinBoundsAndCenter
67
{
68
__forceinline BinBoundsAndCenter(Scene* scene, const LinearSpace3fa& space)
69
: scene(scene), space(space) {}
70
71
/*! returns center for binning */
72
__forceinline Vec3fa binCenter(const PrimRef& ref) const
73
{
74
Geometry* mesh = (Geometry*) scene->get(ref.geomID());
75
BBox3fa bounds = mesh->vbounds(space,ref.primID());
76
return embree::center2(bounds);
77
}
78
79
/*! returns bounds and centroid used for binning */
80
__forceinline void binBoundsAndCenter(const PrimRef& ref, BBox3fa& bounds_o, Vec3fa& center_o) const
81
{
82
Geometry* mesh = (Geometry*) scene->get(ref.geomID());
83
BBox3fa bounds = mesh->vbounds(space,ref.primID());
84
bounds_o = bounds;
85
center_o = embree::center2(bounds);
86
}
87
88
private:
89
Scene* scene;
90
const LinearSpace3fa space;
91
};
92
93
/*! finds the best split */
94
__forceinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize, const LinearSpace3fa& space)
95
{
96
if (likely(pinfo.size() < 10000))
97
return find_template<false>(pinfo,logBlockSize,space);
98
else
99
return find_template<true>(pinfo,logBlockSize,space);
100
}
101
102
/*! finds the best split */
103
template<bool parallel>
104
const Split find_template(const PrimInfoRange& set, const size_t logBlockSize, const LinearSpace3fa& space)
105
{
106
Binner binner(empty);
107
const BinMapping<BINS> mapping(set);
108
BinBoundsAndCenter binBoundsAndCenter(scene,space);
109
bin_serial_or_parallel<parallel>(binner,prims,set.begin(),set.end(),size_t(4096),mapping,binBoundsAndCenter);
110
return binner.best(mapping,logBlockSize);
111
}
112
113
/*! array partitioning */
114
__forceinline void split(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
115
{
116
if (likely(set.size() < 10000))
117
split_template<false>(split,space,set,lset,rset);
118
else
119
split_template<true>(split,space,set,lset,rset);
120
}
121
122
/*! array partitioning */
123
template<bool parallel>
124
__forceinline void split_template(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
125
{
126
if (!split.valid()) {
127
deterministic_order(set);
128
return splitFallback(set,lset,rset);
129
}
130
131
const size_t begin = set.begin();
132
const size_t end = set.end();
133
CentGeomBBox3fa local_left(empty);
134
CentGeomBBox3fa local_right(empty);
135
const int splitPos = split.pos;
136
const int splitDim = split.dim;
137
BinBoundsAndCenter binBoundsAndCenter(scene,space);
138
139
size_t center = 0;
140
if (likely(set.size() < 10000))
141
center = serial_partitioning(prims,begin,end,local_left,local_right,
142
[&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
143
[] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
144
else
145
center = parallel_partitioning(prims,begin,end,EmptyTy(),local_left,local_right,
146
[&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
147
[] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
148
[] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
149
128);
150
151
new (&lset) PrimInfoRange(begin,center,local_left);
152
new (&rset) PrimInfoRange(center,end,local_right);
153
assert(area(lset.geomBounds) >= 0.0f);
154
assert(area(rset.geomBounds) >= 0.0f);
155
}
156
157
void deterministic_order(const range<size_t>& set)
158
{
159
/* required as parallel partition destroys original primitive order */
160
std::sort(&prims[set.begin()],&prims[set.end()]);
161
}
162
163
void splitFallback(const range<size_t>& set, PrimInfoRange& lset, PrimInfoRange& rset)
164
{
165
const size_t begin = set.begin();
166
const size_t end = set.end();
167
const size_t center = (begin + end)/2;
168
169
CentGeomBBox3fa left(empty);
170
for (size_t i=begin; i<center; i++)
171
left.extend_center2(prims[i]);
172
new (&lset) PrimInfoRange(begin,center,left);
173
174
CentGeomBBox3fa right(empty);
175
for (size_t i=center; i<end; i++)
176
right.extend_center2(prims[i]);
177
new (&rset) PrimInfoRange(center,end,right);
178
}
179
180
private:
181
Scene* const scene;
182
PrimRef* const prims;
183
};
184
185
/*! Performs standard object binning */
186
template<typename PrimRefMB, size_t BINS>
187
struct UnalignedHeuristicArrayBinningMB
188
{
189
typedef BinSplit<BINS> Split;
190
typedef typename PrimRefMB::BBox BBox;
191
typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
192
193
static const size_t PARALLEL_THRESHOLD = 3 * 1024;
194
static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
195
static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
196
197
UnalignedHeuristicArrayBinningMB(Scene* scene)
198
: scene(scene) {}
199
200
const LinearSpace3fa computeAlignedSpaceMB(Scene* scene, const SetMB& set)
201
{
202
Vec3fa axis0(0,0,1);
203
uint64_t bestGeomPrimID = -1;
204
205
/*! find curve with minimum ID that defines valid direction */
206
for (size_t i=set.begin(); i<set.end(); i++)
207
{
208
const PrimRefMB& prim = (*set.prims)[i];
209
const unsigned int geomID = prim.geomID();
210
const unsigned int primID = prim.primID();
211
const uint64_t geomprimID = prim.ID64();
212
if (geomprimID >= bestGeomPrimID) continue;
213
214
const Geometry* mesh = scene->get(geomID);
215
const range<int> tbounds = mesh->timeSegmentRange(set.time_range);
216
if (tbounds.size() == 0) continue;
217
218
const size_t t = (tbounds.begin()+tbounds.end())/2;
219
const Vec3fa axis1 = mesh->computeDirection(primID,t);
220
if (sqr_length(axis1) > 1E-18f) {
221
axis0 = normalize(axis1);
222
bestGeomPrimID = geomprimID;
223
}
224
}
225
226
return frame(axis0).transposed();
227
}
228
229
struct BinBoundsAndCenter
230
{
231
__forceinline BinBoundsAndCenter(Scene* scene, BBox1f time_range, const LinearSpace3fa& space)
232
: scene(scene), time_range(time_range), space(space) {}
233
234
/*! returns center for binning */
235
template<typename PrimRef>
236
__forceinline Vec3fa binCenter(const PrimRef& ref) const
237
{
238
Geometry* mesh = scene->get(ref.geomID());
239
LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
240
return center2(lbounds.interpolate(0.5f));
241
}
242
243
/*! returns bounds and centroid used for binning */
244
__noinline void binBoundsAndCenter (const PrimRefMB& ref, BBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
245
{
246
Geometry* mesh = scene->get(ref.geomID());
247
LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
248
bounds_o = lbounds.interpolate(0.5f);
249
center_o = center2(bounds_o);
250
}
251
252
/*! returns bounds and centroid used for binning */
253
__noinline void binBoundsAndCenter (const PrimRefMB& ref, LBBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
254
{
255
Geometry* mesh = scene->get(ref.geomID());
256
LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
257
bounds_o = lbounds;
258
center_o = center2(lbounds.interpolate(0.5f));
259
}
260
261
private:
262
Scene* scene;
263
BBox1f time_range;
264
const LinearSpace3fa space;
265
};
266
267
/*! finds the best split */
268
const Split find(const SetMB& set, const size_t logBlockSize, const LinearSpace3fa& space)
269
{
270
BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
271
ObjectBinner binner(empty);
272
const BinMapping<BINS> mapping(set.size(),set.centBounds);
273
bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping,binBoundsAndCenter);
274
Split osplit = binner.best(mapping,logBlockSize);
275
osplit.sah *= set.time_range.size();
276
if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
277
return osplit;
278
}
279
280
/*! array partitioning */
281
__forceinline void split(const Split& split, const LinearSpace3fa& space, const SetMB& set, SetMB& lset, SetMB& rset)
282
{
283
BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
284
const size_t begin = set.begin();
285
const size_t end = set.end();
286
PrimInfoMB left = empty;
287
PrimInfoMB right = empty;
288
const vint4 vSplitPos(split.pos);
289
const vbool4 vSplitMask(1 << split.dim);
290
auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref,binBoundsAndCenter) < vSplitPos) & vSplitMask); };
291
auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
292
auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
293
size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
294
new (&lset) SetMB(left,set.prims,range<size_t>(begin,center),set.time_range);
295
new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
296
}
297
298
private:
299
Scene* scene;
300
};
301
}
302
}
303
304