Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.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
struct PrimInfoRange : public CentGeomBBox3fa, public range<size_t>
13
{
14
__forceinline PrimInfoRange () {
15
}
16
17
__forceinline PrimInfoRange(const PrimInfo& pinfo)
18
: CentGeomBBox3fa(pinfo), range<size_t>(pinfo.begin,pinfo.end) {}
19
20
__forceinline PrimInfoRange(EmptyTy)
21
: CentGeomBBox3fa(EmptyTy()), range<size_t>(0,0) {}
22
23
__forceinline PrimInfoRange (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds)
24
: CentGeomBBox3fa(centGeomBounds), range<size_t>(begin,end) {}
25
26
__forceinline PrimInfoRange (range<size_t> r, const CentGeomBBox3fa& centGeomBounds)
27
: CentGeomBBox3fa(centGeomBounds), range<size_t>(r) {}
28
29
__forceinline float leafSAH() const {
30
return expectedApproxHalfArea(geomBounds)*float(size());
31
}
32
33
__forceinline float leafSAH(size_t block_shift) const {
34
return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
35
}
36
37
__forceinline range<size_t> get_range() const {
38
return range<size_t>(begin(),end());
39
}
40
41
template<typename PrimRef>
42
__forceinline void add_primref(const PrimRef& prim)
43
{
44
CentGeomBBox3fa::extend_primref(prim);
45
_end++;
46
}
47
};
48
49
inline void performFallbackSplit(PrimRef* const prims, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
50
{
51
const size_t begin = pinfo.begin();
52
const size_t end = pinfo.end();
53
const size_t center = (begin + end)/2;
54
55
CentGeomBBox3fa left(empty);
56
for (size_t i=begin; i<center; i++)
57
left.extend_center2(prims[i]);
58
new (&linfo) PrimInfoRange(begin,center,left);
59
60
CentGeomBBox3fa right(empty);
61
for (size_t i=center; i<end; i++)
62
right.extend_center2(prims[i]);
63
new (&rinfo) PrimInfoRange(center,end,right);
64
}
65
66
template<typename Type, typename getTypeFunc>
67
inline void performTypeSplit(const getTypeFunc& getType, Type type, PrimRef* const prims, range<size_t> range, PrimInfoRange& linfo, PrimInfoRange& rinfo)
68
{
69
CentGeomBBox3fa local_left(empty), local_right(empty);
70
auto isLeft = [&] (const PrimRef& ref) { return type == getType(ref.geomID()); };
71
const size_t center = serial_partitioning(prims,range.begin(),range.end(),local_left,local_right,isLeft,CentGeomBBox3fa::extend_ref);
72
linfo = PrimInfoRange(make_range(range.begin(),center ),local_left);
73
rinfo = PrimInfoRange(make_range(center ,range.end()),local_right);
74
}
75
76
/*! Performs standard object binning */
77
template<typename PrimRef, size_t BINS>
78
struct HeuristicArrayBinningSAH
79
{
80
typedef BinSplit<BINS> Split;
81
typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
82
typedef range<size_t> Set;
83
84
static const size_t PARALLEL_THRESHOLD = 3 * 1024;
85
static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
86
static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
87
88
__forceinline HeuristicArrayBinningSAH ()
89
: prims(nullptr) {}
90
91
/*! remember prim array */
92
__forceinline HeuristicArrayBinningSAH (PrimRef* prims)
93
: prims(prims) {}
94
95
/*! finds the best split */
96
__noinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize)
97
{
98
if (likely(pinfo.size() < PARALLEL_THRESHOLD))
99
return find_template<false>(pinfo,logBlockSize);
100
else
101
return find_template<true>(pinfo,logBlockSize);
102
}
103
104
template<bool parallel>
105
__forceinline const Split find_template(const PrimInfoRange& pinfo, const size_t logBlockSize)
106
{
107
Binner binner(empty);
108
const BinMapping<BINS> mapping(pinfo);
109
bin_serial_or_parallel<parallel>(binner,prims,pinfo.begin(),pinfo.end(),PARALLEL_FIND_BLOCK_SIZE,mapping);
110
return binner.best(mapping,logBlockSize);
111
}
112
113
/*! finds the best split */
114
__noinline const Split find_block_size(const PrimInfoRange& pinfo, const size_t blockSize)
115
{
116
if (likely(pinfo.size() < PARALLEL_THRESHOLD))
117
return find_block_size_template<false>(pinfo,blockSize);
118
else
119
return find_block_size_template<true>(pinfo,blockSize);
120
}
121
122
template<bool parallel>
123
__forceinline const Split find_block_size_template(const PrimInfoRange& pinfo, const size_t blockSize)
124
{
125
Binner binner(empty);
126
const BinMapping<BINS> mapping(pinfo);
127
bin_serial_or_parallel<parallel>(binner,prims,pinfo.begin(),pinfo.end(),PARALLEL_FIND_BLOCK_SIZE,mapping);
128
return binner.best_block_size(mapping,blockSize);
129
}
130
131
/*! array partitioning */
132
__forceinline void split(const Split& split, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
133
{
134
if (likely(pinfo.size() < PARALLEL_THRESHOLD))
135
split_template<false>(split,pinfo,linfo,rinfo);
136
else
137
split_template<true>(split,pinfo,linfo,rinfo);
138
}
139
140
template<bool parallel>
141
__forceinline void split_template(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)
142
{
143
if (!split.valid()) {
144
deterministic_order(set);
145
return splitFallback(set,lset,rset);
146
}
147
148
const size_t begin = set.begin();
149
const size_t end = set.end();
150
CentGeomBBox3fa local_left(empty);
151
CentGeomBBox3fa local_right(empty);
152
const unsigned int splitPos = split.pos;
153
const unsigned int splitDim = split.dim;
154
const unsigned int splitDimMask = (unsigned int)1 << splitDim;
155
156
const typename Binner::vint vSplitPos(splitPos);
157
const typename Binner::vbool vSplitMask(splitDimMask);
158
auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
159
160
size_t center = 0;
161
if (!parallel)
162
center = serial_partitioning(prims,begin,end,local_left,local_right,isLeft,
163
[] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
164
else
165
center = parallel_partitioning(
166
prims,begin,end,EmptyTy(),local_left,local_right,isLeft,
167
[] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
168
[] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
169
PARALLEL_PARTITION_BLOCK_SIZE);
170
171
new (&lset) PrimInfoRange(begin,center,local_left);
172
new (&rset) PrimInfoRange(center,end,local_right);
173
assert(area(lset.geomBounds) >= 0.0f);
174
assert(area(rset.geomBounds) >= 0.0f);
175
}
176
177
void deterministic_order(const PrimInfoRange& pinfo)
178
{
179
/* required as parallel partition destroys original primitive order */
180
std::sort(&prims[pinfo.begin()],&prims[pinfo.end()]);
181
}
182
183
void splitFallback(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo) {
184
performFallbackSplit(prims,pinfo,linfo,rinfo);
185
}
186
187
void splitByGeometry(const range<size_t>& range, PrimInfoRange& linfo, PrimInfoRange& rinfo)
188
{
189
assert(range.size() > 1);
190
CentGeomBBox3fa left(empty);
191
CentGeomBBox3fa right(empty);
192
unsigned int geomID = prims[range.begin()].geomID();
193
size_t center = serial_partitioning(prims,range.begin(),range.end(),left,right,
194
[&] ( const PrimRef& prim ) { return prim.geomID() == geomID; },
195
[ ] ( CentGeomBBox3fa& a, const PrimRef& ref ) { a.extend_center2(ref); });
196
197
new (&linfo) PrimInfoRange(range.begin(),center,left);
198
new (&rinfo) PrimInfoRange(center,range.end(),right);
199
}
200
201
private:
202
PrimRef* const prims;
203
};
204
205
#if !defined(RTHWIF_STANDALONE)
206
207
/*! Performs standard object binning */
208
template<typename PrimRefMB, size_t BINS>
209
struct HeuristicArrayBinningMB
210
{
211
typedef BinSplit<BINS> Split;
212
typedef typename PrimRefMB::BBox BBox;
213
typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
214
static const size_t PARALLEL_THRESHOLD = 3 * 1024;
215
static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
216
static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
217
218
/*! finds the best split */
219
const Split find(const SetMB& set, const size_t logBlockSize)
220
{
221
ObjectBinner binner(empty);
222
const BinMapping<BINS> mapping(set.size(),set.centBounds);
223
bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping);
224
Split osplit = binner.best(mapping,logBlockSize);
225
osplit.sah *= set.time_range.size();
226
if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
227
return osplit;
228
}
229
230
/*! array partitioning */
231
__forceinline void split(const Split& split, const SetMB& set, SetMB& lset, SetMB& rset)
232
{
233
const size_t begin = set.begin();
234
const size_t end = set.end();
235
PrimInfoMB left = empty;
236
PrimInfoMB right = empty;
237
const vint4 vSplitPos(split.pos);
238
const vbool4 vSplitMask(1 << split.dim);
239
auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref) < vSplitPos) & vSplitMask); };
240
auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
241
auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
242
size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
243
new (&lset) SetMB(left, set.prims,range<size_t>(begin,center),set.time_range);
244
new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
245
}
246
};
247
#endif
248
}
249
}
250
251