1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#include "scene.h"
5
6#include "../bvh/bvh4_factory.h"
7#include "../bvh/bvh8_factory.h"
8#include "../../common/algorithms/parallel_reduce.h"
9
10namespace embree
11{
12 /* error raising rtcIntersect and rtcOccluded functions */
13 void missing_rtcCommit() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); }
14 void invalid_rtcIntersect1() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect and rtcOccluded not enabled"); }
15 void invalid_rtcIntersect4() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect4 and rtcOccluded4 not enabled"); }
16 void invalid_rtcIntersect8() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect8 and rtcOccluded8 not enabled"); }
17 void invalid_rtcIntersect16() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect16 and rtcOccluded16 not enabled"); }
18 void invalid_rtcIntersectN() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectN and rtcOccludedN not enabled"); }
19
20 Scene::Scene (Device* device)
21 : device(device),
22 flags_modified(true), enabled_geometry_types(0),
23 scene_flags(RTC_SCENE_FLAG_NONE),
24 quality_flags(RTC_BUILD_QUALITY_MEDIUM),
25 is_build(false), modified(true),
26 progressInterface(this), progress_monitor_function(nullptr), progress_monitor_ptr(nullptr), progress_monitor_counter(0)
27 {
28 device->refInc();
29
30 intersectors = Accel::Intersectors(missing_rtcCommit);
31
32 /* one can overwrite flags through device for debugging */
33 if (device->quality_flags != -1)
34 quality_flags = (RTCBuildQuality) device->quality_flags;
35 if (device->scene_flags != -1)
36 scene_flags = (RTCSceneFlags) device->scene_flags;
37 }
38
39 Scene::~Scene() noexcept
40 {
41 device->refDec();
42 }
43
44 void Scene::printStatistics()
45 {
46 /* calculate maximum number of time segments */
47 unsigned max_time_steps = 0;
48 for (size_t i=0; i<size(); i++) {
49 if (!get(i)) continue;
50 max_time_steps = max(max_time_steps,get(i)->numTimeSteps);
51 }
52
53 /* initialize vectors*/
54 std::vector<size_t> statistics[Geometry::GTY_END];
55 for (size_t i=0; i<Geometry::GTY_END; i++)
56 statistics[i].resize(max_time_steps);
57
58 /* gather statistics */
59 for (size_t i=0; i<size(); i++)
60 {
61 if (!get(i)) continue;
62 int ty = get(i)->getType();
63 assert(ty<Geometry::GTY_END);
64 int timesegments = get(i)->numTimeSegments();
65 assert((unsigned int)timesegments < max_time_steps);
66 statistics[ty][timesegments] += get(i)->size();
67 }
68
69 /* print statistics */
70 std::cout << std::setw(23) << "segments" << ": ";
71 for (size_t t=0; t<max_time_steps; t++)
72 std::cout << std::setw(10) << t;
73 std::cout << std::endl;
74
75 std::cout << "-------------------------";
76 for (size_t t=0; t<max_time_steps; t++)
77 std::cout << "----------";
78 std::cout << std::endl;
79
80 for (size_t p=0; p<Geometry::GTY_END; p++)
81 {
82 if (std::string(Geometry::gtype_names[p]) == "") continue;
83 std::cout << std::setw(23) << Geometry::gtype_names[p] << ": ";
84 for (size_t t=0; t<max_time_steps; t++)
85 std::cout << std::setw(10) << statistics[p][t];
86 std::cout << std::endl;
87 }
88 }
89
90 void Scene::createTriangleAccel()
91 {
92#if defined(EMBREE_GEOMETRY_TRIANGLE)
93 if (device->tri_accel == "default")
94 {
95 if (quality_flags != RTC_BUILD_QUALITY_LOW)
96 {
97 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
98 switch (mode) {
99 case /*0b00*/ 0:
100#if defined (EMBREE_TARGET_SIMD8)
101 if (device->canUseAVX())
102 {
103 if (quality_flags == RTC_BUILD_QUALITY_HIGH)
104 accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
105 else
106 accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
107 }
108 else
109#endif
110 {
111 if (quality_flags == RTC_BUILD_QUALITY_HIGH)
112 accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
113 else
114 accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
115 }
116 break;
117
118 case /*0b01*/ 1:
119#if defined (EMBREE_TARGET_SIMD8)
120 if (device->canUseAVX())
121 accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
122 else
123#endif
124 accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
125
126 break;
127 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
128 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
129 }
130 }
131 else /* dynamic */
132 {
133#if defined (EMBREE_TARGET_SIMD8)
134 if (device->canUseAVX())
135 {
136 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
137 switch (mode) {
138 case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
139 case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
140 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
141 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
142 }
143 }
144 else
145#endif
146 {
147 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
148 switch (mode) {
149 case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
150 case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
151 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
152 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
153 }
154 }
155 }
156 }
157 else if (device->tri_accel == "bvh4.triangle4") accels_add(device->bvh4_factory->BVH4Triangle4 (this));
158 else if (device->tri_accel == "bvh4.triangle4v") accels_add(device->bvh4_factory->BVH4Triangle4v(this));
159 else if (device->tri_accel == "bvh4.triangle4i") accels_add(device->bvh4_factory->BVH4Triangle4i(this));
160 else if (device->tri_accel == "qbvh4.triangle4i") accels_add(device->bvh4_factory->BVH4QuantizedTriangle4i(this));
161
162#if defined (EMBREE_TARGET_SIMD8)
163 else if (device->tri_accel == "bvh8.triangle4") accels_add(device->bvh8_factory->BVH8Triangle4 (this));
164 else if (device->tri_accel == "bvh8.triangle4v") accels_add(device->bvh8_factory->BVH8Triangle4v(this));
165 else if (device->tri_accel == "bvh8.triangle4i") accels_add(device->bvh8_factory->BVH8Triangle4i(this));
166 else if (device->tri_accel == "qbvh8.triangle4i") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4i(this));
167 else if (device->tri_accel == "qbvh8.triangle4") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4(this));
168#endif
169 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown triangle acceleration structure "+device->tri_accel);
170#endif
171 }
172
173 void Scene::createTriangleMBAccel()
174 {
175#if defined(EMBREE_GEOMETRY_TRIANGLE)
176 if (device->tri_accel_mb == "default")
177 {
178 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
179
180#if defined (EMBREE_TARGET_SIMD8)
181 if (device->canUseAVX2()) // BVH8 reduces performance on AVX only-machines
182 {
183 switch (mode) {
184 case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
185 case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
186 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
187 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
188 }
189 }
190 else
191#endif
192 {
193 switch (mode) {
194 case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
195 case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
196 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
197 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
198 }
199 }
200 }
201 else if (device->tri_accel_mb == "bvh4.triangle4imb") accels_add(device->bvh4_factory->BVH4Triangle4iMB(this));
202 else if (device->tri_accel_mb == "bvh4.triangle4vmb") accels_add(device->bvh4_factory->BVH4Triangle4vMB(this));
203#if defined (EMBREE_TARGET_SIMD8)
204 else if (device->tri_accel_mb == "bvh8.triangle4imb") accels_add(device->bvh8_factory->BVH8Triangle4iMB(this));
205 else if (device->tri_accel_mb == "bvh8.triangle4vmb") accels_add(device->bvh8_factory->BVH8Triangle4vMB(this));
206#endif
207 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur triangle acceleration structure "+device->tri_accel_mb);
208#endif
209 }
210
211 void Scene::createQuadAccel()
212 {
213#if defined(EMBREE_GEOMETRY_QUAD)
214 if (device->quad_accel == "default")
215 {
216 if (quality_flags != RTC_BUILD_QUALITY_LOW)
217 {
218 /* static */
219 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
220 switch (mode) {
221 case /*0b00*/ 0:
222#if defined (EMBREE_TARGET_SIMD8)
223 if (device->canUseAVX())
224 {
225 if (quality_flags == RTC_BUILD_QUALITY_HIGH)
226 accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
227 else
228 accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
229 }
230 else
231#endif
232 {
233 if (quality_flags == RTC_BUILD_QUALITY_HIGH)
234 accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
235 else
236 accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
237 }
238 break;
239
240 case /*0b01*/ 1:
241#if defined (EMBREE_TARGET_SIMD8)
242 if (device->canUseAVX())
243 accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
244 else
245#endif
246 accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
247 break;
248
249 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST)); break;
250 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
251 }
252 }
253 else /* dynamic */
254 {
255#if defined (EMBREE_TARGET_SIMD8)
256 if (device->canUseAVX())
257 {
258 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
259 switch (mode) {
260 case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
261 case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
262 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
263 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
264 }
265 }
266 else
267#endif
268 {
269 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
270 switch (mode) {
271 case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
272 case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
273 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
274 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
275 }
276 }
277 }
278 }
279 else if (device->quad_accel == "bvh4.quad4v") accels_add(device->bvh4_factory->BVH4Quad4v(this));
280 else if (device->quad_accel == "bvh4.quad4i") accels_add(device->bvh4_factory->BVH4Quad4i(this));
281 else if (device->quad_accel == "qbvh4.quad4i") accels_add(device->bvh4_factory->BVH4QuantizedQuad4i(this));
282
283#if defined (EMBREE_TARGET_SIMD8)
284 else if (device->quad_accel == "bvh8.quad4v") accels_add(device->bvh8_factory->BVH8Quad4v(this));
285 else if (device->quad_accel == "bvh8.quad4i") accels_add(device->bvh8_factory->BVH8Quad4i(this));
286 else if (device->quad_accel == "qbvh8.quad4i") accels_add(device->bvh8_factory->BVH8QuantizedQuad4i(this));
287#endif
288 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad acceleration structure "+device->quad_accel);
289#endif
290 }
291
292 void Scene::createQuadMBAccel()
293 {
294#if defined(EMBREE_GEOMETRY_QUAD)
295 if (device->quad_accel_mb == "default")
296 {
297 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
298 switch (mode) {
299 case /*0b00*/ 0:
300#if defined (EMBREE_TARGET_SIMD8)
301 if (device->canUseAVX())
302 accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
303 else
304#endif
305 accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
306 break;
307
308 case /*0b01*/ 1:
309#if defined (EMBREE_TARGET_SIMD8)
310 if (device->canUseAVX())
311 accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
312 else
313#endif
314 accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
315 break;
316
317 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
318 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
319 }
320 }
321 else if (device->quad_accel_mb == "bvh4.quad4imb") accels_add(device->bvh4_factory->BVH4Quad4iMB(this));
322#if defined (EMBREE_TARGET_SIMD8)
323 else if (device->quad_accel_mb == "bvh8.quad4imb") accels_add(device->bvh8_factory->BVH8Quad4iMB(this));
324#endif
325 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad motion blur acceleration structure "+device->quad_accel_mb);
326#endif
327 }
328
329 void Scene::createHairAccel()
330 {
331#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
332 if (device->hair_accel == "default")
333 {
334 int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
335#if defined (EMBREE_TARGET_SIMD8)
336 if (device->canUseAVX2()) // only enable on HSW machines, for SNB this codepath is slower
337 {
338 switch (mode) {
339 case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST)); break;
340 case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::ROBUST)); break;
341 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST)); break;
342 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::ROBUST)); break;
343 }
344 }
345 else
346#endif
347 {
348 switch (mode) {
349 case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST)); break;
350 case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::ROBUST)); break;
351 case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST)); break;
352 case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::ROBUST)); break;
353 }
354 }
355 }
356 else if (device->hair_accel == "bvh4obb.virtualcurve4v" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST));
357 else if (device->hair_accel == "bvh4obb.virtualcurve4i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST));
358#if defined (EMBREE_TARGET_SIMD8)
359 else if (device->hair_accel == "bvh8obb.virtualcurve8v" ) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST));
360 else if (device->hair_accel == "bvh4obb.virtualcurve8i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST));
361#endif
362 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown hair acceleration structure "+device->hair_accel);
363#endif
364 }
365
366 void Scene::createHairMBAccel()
367 {
368#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
369 if (device->hair_accel_mb == "default")
370 {
371#if defined (EMBREE_TARGET_SIMD8)
372 if (device->canUseAVX2()) // only enable on HSW machines, on SNB this codepath is slower
373 {
374 if (isRobustAccel()) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::ROBUST));
375 else accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
376 }
377 else
378#endif
379 {
380 if (isRobustAccel()) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::ROBUST));
381 else accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
382 }
383 }
384 else if (device->hair_accel_mb == "bvh4.virtualcurve4imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
385
386#if defined (EMBREE_TARGET_SIMD8)
387 else if (device->hair_accel_mb == "bvh4.virtualcurve8imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
388 else if (device->hair_accel_mb == "bvh8.virtualcurve8imb") accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
389#endif
390 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur hair acceleration structure "+device->hair_accel_mb);
391#endif
392 }
393
394 void Scene::createSubdivAccel()
395 {
396#if defined(EMBREE_GEOMETRY_SUBDIVISION)
397 if (device->subdiv_accel == "default") {
398 accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
399 }
400 else if (device->subdiv_accel == "bvh4.grid.eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
401 else if (device->subdiv_accel == "bvh4.subdivpatch1eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
402 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv accel "+device->subdiv_accel);
403#endif
404 }
405
406 void Scene::createSubdivMBAccel()
407 {
408#if defined(EMBREE_GEOMETRY_SUBDIVISION)
409 if (device->subdiv_accel_mb == "default") {
410 accels_add(device->bvh4_factory->BVH4SubdivPatch1MB(this));
411 }
412 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv mblur accel "+device->subdiv_accel_mb);
413#endif
414 }
415
416 void Scene::createUserGeometryAccel()
417 {
418#if defined(EMBREE_GEOMETRY_USER)
419 if (device->object_accel == "default")
420 {
421#if defined (EMBREE_TARGET_SIMD8)
422 if (device->canUseAVX() && !isCompactAccel())
423 {
424 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
425 accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::STATIC));
426 } else {
427 accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
428 }
429 }
430 else
431#endif
432 {
433 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
434 accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::STATIC));
435 } else {
436 accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
437 }
438 }
439 }
440 else if (device->object_accel == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometry(this));
441#if defined (EMBREE_TARGET_SIMD8)
442 else if (device->object_accel == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometry(this));
443#endif
444 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry accel "+device->object_accel);
445#endif
446 }
447
448 void Scene::createUserGeometryMBAccel()
449 {
450#if defined(EMBREE_GEOMETRY_USER)
451 if (device->object_accel_mb == "default" ) {
452#if defined (EMBREE_TARGET_SIMD8)
453 if (device->canUseAVX() && !isCompactAccel())
454 accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
455 else
456#endif
457 accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
458 }
459 else if (device->object_accel_mb == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
460#if defined (EMBREE_TARGET_SIMD8)
461 else if (device->object_accel_mb == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
462#endif
463 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry mblur accel "+device->object_accel_mb);
464#endif
465 }
466
467 void Scene::createInstanceAccel()
468 {
469#if defined(EMBREE_GEOMETRY_INSTANCE)
470 // if (device->object_accel == "default")
471 {
472#if defined (EMBREE_TARGET_SIMD8)
473 if (device->canUseAVX() && !isCompactAccel()) {
474 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
475 accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::STATIC));
476 } else {
477 accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
478 }
479 }
480 else
481#endif
482 {
483 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
484 accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::STATIC));
485 } else {
486 accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
487 }
488 }
489 }
490 // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
491#endif
492 }
493
494 void Scene::createInstanceMBAccel()
495 {
496#if defined(EMBREE_GEOMETRY_INSTANCE)
497 //if (device->instance_accel_mb == "default")
498 {
499#if defined (EMBREE_TARGET_SIMD8)
500 if (device->canUseAVX() && !isCompactAccel())
501 accels_add(device->bvh8_factory->BVH8InstanceMB(this, false));
502 else
503#endif
504 accels_add(device->bvh4_factory->BVH4InstanceMB(this, false));
505 }
506 //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
507#endif
508 }
509
510 void Scene::createInstanceExpensiveAccel()
511 {
512#if defined(EMBREE_GEOMETRY_INSTANCE)
513 // if (device->object_accel == "default")
514 {
515#if defined (EMBREE_TARGET_SIMD8)
516 if (device->canUseAVX() && !isCompactAccel()) {
517 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
518 accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::STATIC));
519 } else {
520 accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
521 }
522 }
523 else
524#endif
525 {
526 if (quality_flags != RTC_BUILD_QUALITY_LOW) {
527 accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::STATIC));
528 } else {
529 accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
530 }
531 }
532 }
533 // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
534#endif
535 }
536
537 void Scene::createInstanceExpensiveMBAccel()
538 {
539#if defined(EMBREE_GEOMETRY_INSTANCE)
540 //if (device->instance_accel_mb == "default")
541 {
542#if defined (EMBREE_TARGET_SIMD8)
543 if (device->canUseAVX() && !isCompactAccel())
544 accels_add(device->bvh8_factory->BVH8InstanceMB(this, true));
545 else
546#endif
547 accels_add(device->bvh4_factory->BVH4InstanceMB(this, true));
548 }
549 //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
550#endif
551 }
552
553 void Scene::createGridAccel()
554 {
555 BVHFactory::IntersectVariant ivariant = isRobustAccel() ? BVHFactory::IntersectVariant::ROBUST : BVHFactory::IntersectVariant::FAST;
556#if defined(EMBREE_GEOMETRY_GRID)
557 if (device->grid_accel == "default")
558 {
559#if defined (EMBREE_TARGET_SIMD8)
560 if (device->canUseAVX() && !isCompactAccel())
561 {
562 accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
563 }
564 else
565#endif
566 {
567 accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
568 }
569 }
570 else if (device->grid_accel == "bvh4.grid") accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
571#if defined (EMBREE_TARGET_SIMD8)
572 else if (device->grid_accel == "bvh8.grid") accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
573#endif
574 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid accel "+device->grid_accel);
575#endif
576
577 }
578
579 void Scene::createGridMBAccel()
580 {
581#if defined(EMBREE_GEOMETRY_GRID)
582 if (device->grid_accel_mb == "default")
583 {
584 accels_add(device->bvh4_factory->BVH4GridMB(this,BVHFactory::BuildVariant::STATIC));
585 }
586 else if (device->grid_accel_mb == "bvh4mb.grid") accels_add(device->bvh4_factory->BVH4GridMB(this));
587 else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid mb accel "+device->grid_accel);
588#endif
589
590 }
591
592 void Scene::clear() {
593 }
594
595 unsigned Scene::bind(unsigned geomID, Ref<Geometry> geometry)
596 {
597 Lock<SpinLock> lock(geometriesMutex);
598 if (geomID == RTC_INVALID_GEOMETRY_ID) {
599 geomID = id_pool.allocate();
600 if (geomID == RTC_INVALID_GEOMETRY_ID)
601 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"too many geometries inside scene");
602 }
603 else
604 {
605 if (!id_pool.add(geomID))
606 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID provided");
607 }
608 if (geomID >= geometries.size()) {
609 geometries.resize(geomID+1);
610 vertices.resize(geomID+1);
611 geometryModCounters_.resize(geomID+1);
612 }
613 geometries[geomID] = geometry;
614 geometryModCounters_[geomID] = 0;
615 if (geometry->isEnabled()) {
616 setModified ();
617 }
618 return geomID;
619 }
620
621 void Scene::detachGeometry(size_t geomID)
622 {
623 Lock<SpinLock> lock(geometriesMutex);
624
625 if (geomID >= geometries.size())
626 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID");
627
628 Ref<Geometry>& geometry = geometries[geomID];
629 if (geometry == null)
630 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry");
631
632 setModified ();
633 accels_deleteGeometry(unsigned(geomID));
634 id_pool.deallocate((unsigned)geomID);
635 geometries[geomID] = null;
636 vertices[geomID] = nullptr;
637 geometryModCounters_[geomID] = 0;
638 }
639
640 void Scene::updateInterface()
641 {
642 is_build = true;
643 }
644
645 void Scene::commit_task ()
646 {
647 checkIfModifiedAndSet ();
648 if (!isModified()) {
649 return;
650 }
651
652 /* print scene statistics */
653 if (device->verbosity(2))
654 printStatistics();
655
656 progress_monitor_counter = 0;
657
658 /* gather scene stats and call preCommit function of each geometry */
659 this->world = parallel_reduce (size_t(0), geometries.size(), GeometryCounts (),
660 [this](const range<size_t>& r)->GeometryCounts
661 {
662 GeometryCounts c;
663 for (auto i=r.begin(); i<r.end(); ++i)
664 {
665 if (geometries[i] && geometries[i]->isEnabled())
666 {
667 geometries[i]->preCommit();
668 geometries[i]->addElementsToCount (c);
669 c.numFilterFunctions += (int) geometries[i]->hasFilterFunctions();
670 }
671 }
672 return c;
673 },
674 std::plus<GeometryCounts>()
675 );
676
677 /* select acceleration structures to build */
678 unsigned int new_enabled_geometry_types = world.enabledGeometryTypesMask();
679 if (flags_modified || new_enabled_geometry_types != enabled_geometry_types)
680 {
681 accels_init();
682
683 /* we need to make all geometries modified, otherwise two level builder will
684 not rebuild currently not modified geometries */
685 parallel_for(geometryModCounters_.size(), [&] ( const size_t i ) {
686 geometryModCounters_[i] = 0;
687 });
688
689 if (getNumPrimitives(TriangleMesh::geom_type,false)) createTriangleAccel();
690 if (getNumPrimitives(TriangleMesh::geom_type,true)) createTriangleMBAccel();
691 if (getNumPrimitives(QuadMesh::geom_type,false)) createQuadAccel();
692 if (getNumPrimitives(QuadMesh::geom_type,true)) createQuadMBAccel();
693 if (getNumPrimitives(GridMesh::geom_type,false)) createGridAccel();
694 if (getNumPrimitives(GridMesh::geom_type,true)) createGridMBAccel();
695 if (getNumPrimitives(SubdivMesh::geom_type,false)) createSubdivAccel();
696 if (getNumPrimitives(SubdivMesh::geom_type,true)) createSubdivMBAccel();
697 if (getNumPrimitives(Geometry::MTY_CURVES,false)) createHairAccel();
698 if (getNumPrimitives(Geometry::MTY_CURVES,true)) createHairMBAccel();
699 if (getNumPrimitives(UserGeometry::geom_type,false)) createUserGeometryAccel();
700 if (getNumPrimitives(UserGeometry::geom_type,true)) createUserGeometryMBAccel();
701 if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,false)) createInstanceAccel();
702 if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,true)) createInstanceMBAccel();
703 if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,false)) createInstanceExpensiveAccel();
704 if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,true)) createInstanceExpensiveMBAccel();
705
706 flags_modified = false;
707 enabled_geometry_types = new_enabled_geometry_types;
708 }
709
710 /* select fast code path if no filter function is present */
711 accels_select(hasFilterFunction());
712
713 /* build all hierarchies of this scene */
714 accels_build();
715
716 /* make static geometry immutable */
717 if (!isDynamicAccel()) {
718 accels_immutable();
719 flags_modified = true; // in non-dynamic mode we have to re-create accels
720 }
721
722 /* call postCommit function of each geometry */
723 parallel_for(geometries.size(), [&] ( const size_t i ) {
724 if (geometries[i] && geometries[i]->isEnabled()) {
725 geometries[i]->postCommit();
726 vertices[i] = geometries[i]->getCompactVertexArray();
727 geometryModCounters_[i] = geometries[i]->getModCounter();
728 }
729 });
730
731 updateInterface();
732
733 if (device->verbosity(2)) {
734 std::cout << "created scene intersector" << std::endl;
735 accels_print(2);
736 std::cout << "selected scene intersector" << std::endl;
737 intersectors.print(2);
738 }
739
740 setModified(false);
741 }
742
743 void Scene::setBuildQuality(RTCBuildQuality quality_flags_i)
744 {
745 if (quality_flags == quality_flags_i) return;
746 quality_flags = quality_flags_i;
747 flags_modified = true;
748 }
749
750 RTCBuildQuality Scene::getBuildQuality() const {
751 return quality_flags;
752 }
753
754 void Scene::setSceneFlags(RTCSceneFlags scene_flags_i)
755 {
756 if (scene_flags == scene_flags_i) return;
757 scene_flags = scene_flags_i;
758 flags_modified = true;
759 }
760
761 RTCSceneFlags Scene::getSceneFlags() const {
762 return scene_flags;
763 }
764
765#if defined(TASKING_INTERNAL)
766
767 void Scene::commit (bool join)
768 {
769 Lock<MutexSys> buildLock(buildMutex,false);
770
771 /* allocates own taskscheduler for each build */
772 Ref<TaskScheduler> scheduler = nullptr;
773 {
774 Lock<MutexSys> lock(schedulerMutex);
775 scheduler = this->scheduler;
776 if (scheduler == null) {
777 buildLock.lock();
778 this->scheduler = scheduler = new TaskScheduler;
779 }
780 }
781
782 /* worker threads join build */
783 if (!buildLock.isLocked())
784 {
785 if (!join)
786 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"use rtcJoinCommitScene to join a build operation");
787
788 scheduler->join();
789 return;
790 }
791
792 /* initiate build */
793 // -- GODOT start --
794 // try {
795 scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join);
796 // }
797 // catch (...) {
798 // accels_clear();
799 // updateInterface();
800 // Lock<MutexSys> lock(schedulerMutex);
801 // this->scheduler = nullptr;
802 // throw;
803 // }
804 // -- GODOT end --
805 }
806
807#endif
808
809#if defined(TASKING_TBB)
810
811 void Scene::commit (bool join)
812 {
813#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
814 if (join)
815 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with this TBB version");
816#endif
817
818 /* try to obtain build lock */
819 Lock<MutexSys> lock(buildMutex,buildMutex.try_lock());
820
821 /* join hierarchy build */
822 if (!lock.isLocked())
823 {
824#if !TASKING_TBB_USE_TASK_ISOLATION
825 if (!join)
826 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invoking rtcCommitScene from multiple threads is not supported with this TBB version");
827#endif
828
829 do {
830
831#if USE_TASK_ARENA
832 if (join) {
833 device->arena->execute([&]{ group.wait(); });
834 }
835 else
836#endif
837 {
838 group.wait();
839 }
840
841 pause_cpu();
842 yield();
843 } while (!buildMutex.try_lock());
844
845 buildMutex.unlock();
846 return;
847 }
848
849 /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
850 const unsigned int mxcsr = _mm_getcsr();
851 _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
852
853 try {
854#if TBB_INTERFACE_VERSION_MAJOR < 8
855 tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits);
856#else
857 tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits | tbb::task_group_context::fp_settings );
858#endif
859 //ctx.set_priority(tbb::priority_high);
860
861#if USE_TASK_ARENA
862 if (join)
863 {
864 device->arena->execute([&]{
865 group.run([&]{
866 tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
867 });
868 group.wait();
869 });
870 }
871 else
872#endif
873 {
874 group.run([&]{
875 tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
876 });
877 group.wait();
878 }
879
880 /* reset MXCSR register again */
881 _mm_setcsr(mxcsr);
882 }
883 catch (...)
884 {
885 /* reset MXCSR register again */
886 _mm_setcsr(mxcsr);
887
888 accels_clear();
889 updateInterface();
890 throw;
891 }
892 }
893#endif
894
895#if defined(TASKING_PPL)
896
897 void Scene::commit (bool join)
898 {
899#if defined(TASKING_PPL)
900 if (join)
901 throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with PPL");
902#endif
903
904 /* try to obtain build lock */
905 Lock<MutexSys> lock(buildMutex);
906
907 checkIfModifiedAndSet ();
908 if (!isModified()) {
909 return;
910 }
911
912 /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
913 const unsigned int mxcsr = _mm_getcsr();
914 _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
915
916 try {
917
918 group.run([&]{
919 concurrency::parallel_for(size_t(0), size_t(1), size_t(1), [&](size_t) { commit_task(); });
920 });
921 group.wait();
922
923 /* reset MXCSR register again */
924 _mm_setcsr(mxcsr);
925 }
926 catch (...)
927 {
928 /* reset MXCSR register again */
929 _mm_setcsr(mxcsr);
930
931 accels_clear();
932 updateInterface();
933 throw;
934 }
935 }
936#endif
937
938 void Scene::setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr)
939 {
940 progress_monitor_function = func;
941 progress_monitor_ptr = ptr;
942 }
943
944 void Scene::progressMonitor(double dn)
945 {
946 if (progress_monitor_function) {
947 size_t n = size_t(dn) + progress_monitor_counter.fetch_add(size_t(dn));
948 if (!progress_monitor_function(progress_monitor_ptr, n / (double(numPrimitives())))) {
949 throw_RTCError(RTC_ERROR_CANCELLED,"progress monitor forced termination");
950 }
951 }
952 }
953}
954