1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#include "device.h"
5#include "../hash.h"
6#include "scene_triangle_mesh.h"
7#include "scene_user_geometry.h"
8#include "scene_instance.h"
9#include "scene_curves.h"
10#include "scene_subdiv_mesh.h"
11
12#include "../subdiv/tessellation_cache.h"
13
14#include "acceln.h"
15#include "geometry.h"
16
17#include "../geometry/cylinder.h"
18
19#include "../bvh/bvh4_factory.h"
20#include "../bvh/bvh8_factory.h"
21
22#include "../../common/tasking/taskscheduler.h"
23#include "../../common/sys/alloc.h"
24
25namespace embree
26{
27 /*! some global variables that can be set via rtcSetParameter1i for debugging purposes */
28 ssize_t Device::debug_int0 = 0;
29 ssize_t Device::debug_int1 = 0;
30 ssize_t Device::debug_int2 = 0;
31 ssize_t Device::debug_int3 = 0;
32
33 DECLARE_SYMBOL2(RayStreamFilterFuncs,rayStreamFilterFuncs);
34
35 static MutexSys g_mutex;
36 static std::map<Device*,size_t> g_cache_size_map;
37 static std::map<Device*,size_t> g_num_threads_map;
38
39 Device::Device (const char* cfg)
40 {
41 /* check that CPU supports lowest ISA */
42 if (!hasISA(ISA)) {
43 throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support " ISA_STR);
44 }
45
46 /* set default frequency level for detected CPU */
47 switch (getCPUModel()) {
48 case CPU::UNKNOWN: frequency_level = FREQUENCY_SIMD256; break;
49 case CPU::XEON_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
50 case CPU::CORE_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
51 case CPU::CORE_TIGER_LAKE: frequency_level = FREQUENCY_SIMD128; break;
52 case CPU::CORE_COMET_LAKE: frequency_level = FREQUENCY_SIMD128; break;
53 case CPU::CORE_CANNON_LAKE:frequency_level = FREQUENCY_SIMD128; break;
54 case CPU::CORE_KABY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
55 case CPU::XEON_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
56 case CPU::CORE_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
57 case CPU::XEON_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
58 case CPU::CORE_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
59 case CPU::XEON_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
60 case CPU::CORE_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
61 case CPU::XEON_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
62 case CPU::CORE_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
63 case CPU::SANDY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
64 case CPU::NEHALEM: frequency_level = FREQUENCY_SIMD128; break;
65 case CPU::CORE2: frequency_level = FREQUENCY_SIMD128; break;
66 case CPU::CORE1: frequency_level = FREQUENCY_SIMD128; break;
67 case CPU::XEON_PHI_KNIGHTS_MILL : frequency_level = FREQUENCY_SIMD512; break;
68 case CPU::XEON_PHI_KNIGHTS_LANDING: frequency_level = FREQUENCY_SIMD512; break;
69 case CPU::ARM: frequency_level = FREQUENCY_SIMD128; break;
70 }
71
72 /* initialize global state */
73#if defined(EMBREE_CONFIG)
74 State::parseString(EMBREE_CONFIG);
75#endif
76 State::parseString(cfg);
77 State::verify();
78
79 /* check whether selected ISA is supported by the HW, as the user could have forced an unsupported ISA */
80 if (!checkISASupport()) {
81 throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support selected ISA");
82 }
83
84 /*! do some internal tests */
85 assert(isa::Cylinder::verify());
86
87 /*! enable huge page support if desired */
88#if defined(__WIN32__)
89 if (State::enable_selockmemoryprivilege)
90 State::hugepages_success &= win_enable_selockmemoryprivilege(State::verbosity(3));
91#endif
92 State::hugepages_success &= os_init(hugepages: State::hugepages,verbose: State::verbosity(N: 3));
93
94 /*! set tessellation cache size */
95 setCacheSize( State::tessellation_cache_size );
96
97 /*! enable some floating point exceptions to catch bugs */
98 if (State::float_exceptions)
99 {
100 int exceptions = _MM_MASK_MASK;
101 //exceptions &= ~_MM_MASK_INVALID;
102 exceptions &= ~_MM_MASK_DENORM;
103 exceptions &= ~_MM_MASK_DIV_ZERO;
104 //exceptions &= ~_MM_MASK_OVERFLOW;
105 //exceptions &= ~_MM_MASK_UNDERFLOW;
106 //exceptions &= ~_MM_MASK_INEXACT;
107 _MM_SET_EXCEPTION_MASK(exceptions);
108 }
109
110 /* print info header */
111 if (State::verbosity(N: 1))
112 print();
113 if (State::verbosity(N: 2))
114 State::print();
115
116 /* register all algorithms */
117 bvh4_factory = make_unique(ptr: new BVH4Factory(enabled_builder_cpu_features, enabled_cpu_features));
118
119#if defined(EMBREE_TARGET_SIMD8)
120 bvh8_factory = make_unique(new BVH8Factory(enabled_builder_cpu_features, enabled_cpu_features));
121#endif
122
123 /* setup tasking system */
124 initTaskingSystem(numThreads);
125
126 /* ray stream SOA to AOS conversion */
127#if defined(EMBREE_RAY_PACKETS)
128 RayStreamFilterFuncsType rayStreamFilterFuncs;
129 SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(enabled_cpu_features,rayStreamFilterFuncs);
130 rayStreamFilters = rayStreamFilterFuncs();
131#endif
132 }
133
134 Device::~Device ()
135 {
136 setCacheSize(0);
137 exitTaskingSystem();
138 }
139
140 std::string getEnabledTargets()
141 {
142 std::string v;
143#if defined(EMBREE_TARGET_SSE2)
144 v += "SSE2 ";
145#endif
146#if defined(EMBREE_TARGET_SSE42)
147 v += "SSE4.2 ";
148#endif
149#if defined(EMBREE_TARGET_AVX)
150 v += "AVX ";
151#endif
152#if defined(EMBREE_TARGET_AVX2)
153 v += "AVX2 ";
154#endif
155#if defined(EMBREE_TARGET_AVX512)
156 v += "AVX512 ";
157#endif
158 return v;
159 }
160
161 std::string getEmbreeFeatures()
162 {
163 std::string v;
164#if defined(EMBREE_RAY_MASK)
165 v += "raymasks ";
166#endif
167#if defined (EMBREE_BACKFACE_CULLING)
168 v += "backfaceculling ";
169#endif
170#if defined (EMBREE_BACKFACE_CULLING_CURVES)
171 v += "backfacecullingcurves ";
172#endif
173#if defined(EMBREE_FILTER_FUNCTION)
174 v += "intersection_filter ";
175#endif
176#if defined (EMBREE_COMPACT_POLYS)
177 v += "compact_polys ";
178#endif
179 return v;
180 }
181
182 void Device::print()
183 {
184 const int cpu_features = getCPUFeatures();
185 std::cout << std::endl;
186 std::cout << "Embree Ray Tracing Kernels " << RTC_VERSION_STRING << " (" << RTC_HASH << ")" << std::endl;
187 std::cout << " Compiler : " << getCompilerName() << std::endl;
188 std::cout << " Build : ";
189#if defined(DEBUG)
190 std::cout << "Debug " << std::endl;
191#else
192 std::cout << "Release " << std::endl;
193#endif
194 std::cout << " Platform : " << getPlatformName() << std::endl;
195 std::cout << " CPU : " << stringOfCPUModel(model: getCPUModel()) << " (" << getCPUVendor() << ")" << std::endl;
196 std::cout << " Threads : " << getNumberOfLogicalThreads() << std::endl;
197 std::cout << " ISA : " << stringOfCPUFeatures(features: cpu_features) << std::endl;
198 std::cout << " Targets : " << supportedTargetList(sse2: cpu_features) << std::endl;
199 const bool hasFTZ = _mm_getcsr() & _MM_FLUSH_ZERO_ON;
200 const bool hasDAZ = _mm_getcsr() & _MM_DENORMALS_ZERO_ON;
201 std::cout << " MXCSR : " << "FTZ=" << hasFTZ << ", DAZ=" << hasDAZ << std::endl;
202 std::cout << " Config" << std::endl;
203 std::cout << " Threads : " << (numThreads ? toString(value: numThreads) : std::string("default")) << std::endl;
204 std::cout << " ISA : " << stringOfCPUFeatures(features: enabled_cpu_features) << std::endl;
205 std::cout << " Targets : " << supportedTargetList(sse2: enabled_cpu_features) << " (supported)" << std::endl;
206 std::cout << " " << getEnabledTargets() << " (compile time enabled)" << std::endl;
207 std::cout << " Features: " << getEmbreeFeatures() << std::endl;
208 std::cout << " Tasking : ";
209#if defined(TASKING_TBB)
210 std::cout << "TBB" << TBB_VERSION_MAJOR << "." << TBB_VERSION_MINOR << " ";
211 #if TBB_INTERFACE_VERSION >= 12002
212 std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << TBB_runtime_interface_version() << " ";
213 #else
214 std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << tbb::TBB_runtime_interface_version() << " ";
215 #endif
216#endif
217#if defined(TASKING_INTERNAL)
218 std::cout << "internal_tasking_system ";
219#endif
220#if defined(TASKING_PPL)
221 std::cout << "PPL ";
222#endif
223 std::cout << std::endl;
224
225 /* check of FTZ and DAZ flags are set in CSR */
226 if (!hasFTZ || !hasDAZ)
227 {
228#if !defined(_DEBUG)
229 if (State::verbosity(N: 1))
230#endif
231 {
232 std::cout << std::endl;
233 std::cout << "================================================================================" << std::endl;
234 std::cout << " WARNING: \"Flush to Zero\" or \"Denormals are Zero\" mode not enabled " << std::endl
235 << " in the MXCSR control and status register. This can have a severe " << std::endl
236 << " performance impact. Please enable these modes for each application " << std::endl
237 << " thread the following way:" << std::endl
238 << std::endl
239 << " #include \"xmmintrin.h\"" << std::endl
240 << " #include \"pmmintrin.h\"" << std::endl
241 << std::endl
242 << " _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);" << std::endl
243 << " _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);" << std::endl;
244 std::cout << "================================================================================" << std::endl;
245 std::cout << std::endl;
246 }
247 }
248 std::cout << std::endl;
249 }
250
251 void Device::setDeviceErrorCode(RTCError error)
252 {
253 RTCError* stored_error = errorHandler.error();
254 if (*stored_error == RTC_ERROR_NONE)
255 *stored_error = error;
256 }
257
258 RTCError Device::getDeviceErrorCode()
259 {
260 RTCError* stored_error = errorHandler.error();
261 RTCError error = *stored_error;
262 *stored_error = RTC_ERROR_NONE;
263 return error;
264 }
265
266 void Device::setThreadErrorCode(RTCError error)
267 {
268 RTCError* stored_error = g_errorHandler.error();
269 if (*stored_error == RTC_ERROR_NONE)
270 *stored_error = error;
271 }
272
273 RTCError Device::getThreadErrorCode()
274 {
275 RTCError* stored_error = g_errorHandler.error();
276 RTCError error = *stored_error;
277 *stored_error = RTC_ERROR_NONE;
278 return error;
279 }
280
281 void Device::process_error(Device* device, RTCError error, const char* str)
282 {
283 /* store global error code when device construction failed */
284 if (!device)
285 return setThreadErrorCode(error);
286
287 /* print error when in verbose mode */
288 if (device->verbosity(N: 1))
289 {
290 switch (error) {
291 case RTC_ERROR_NONE : std::cerr << "Embree: No error"; break;
292 case RTC_ERROR_UNKNOWN : std::cerr << "Embree: Unknown error"; break;
293 case RTC_ERROR_INVALID_ARGUMENT : std::cerr << "Embree: Invalid argument"; break;
294 case RTC_ERROR_INVALID_OPERATION: std::cerr << "Embree: Invalid operation"; break;
295 case RTC_ERROR_OUT_OF_MEMORY : std::cerr << "Embree: Out of memory"; break;
296 case RTC_ERROR_UNSUPPORTED_CPU : std::cerr << "Embree: Unsupported CPU"; break;
297 default : std::cerr << "Embree: Invalid error code"; break;
298 };
299 if (str) std::cerr << ", (" << str << ")";
300 std::cerr << std::endl;
301 }
302
303 /* call user specified error callback */
304 if (device->error_function)
305 device->error_function(device->error_function_userptr,error,str);
306
307 /* record error code */
308 device->setDeviceErrorCode(error);
309 }
310
311 void Device::memoryMonitor(ssize_t bytes, bool post)
312 {
313 if (State::memory_monitor_function && bytes != 0) {
314 if (!State::memory_monitor_function(State::memory_monitor_userptr,bytes,post)) {
315 if (bytes > 0) { // only throw exception when we allocate memory to never throw inside a destructor
316 throw_RTCError(RTC_ERROR_OUT_OF_MEMORY,"memory monitor forced termination");
317 }
318 }
319 }
320 }
321
322 size_t getMaxNumThreads()
323 {
324 size_t maxNumThreads = 0;
325 for (std::map<Device*,size_t>::iterator i=g_num_threads_map.begin(); i != g_num_threads_map.end(); i++)
326 maxNumThreads = max(a: maxNumThreads, b: (*i).second);
327 if (maxNumThreads == 0)
328 maxNumThreads = std::numeric_limits<size_t>::max();
329 return maxNumThreads;
330 }
331
332 size_t getMaxCacheSize()
333 {
334 size_t maxCacheSize = 0;
335 for (std::map<Device*,size_t>::iterator i=g_cache_size_map.begin(); i!= g_cache_size_map.end(); i++)
336 maxCacheSize = max(a: maxCacheSize, b: (*i).second);
337 return maxCacheSize;
338 }
339
340 void Device::setCacheSize(size_t bytes)
341 {
342#if defined(EMBREE_GEOMETRY_SUBDIVISION)
343 Lock<MutexSys> lock(g_mutex);
344 if (bytes == 0) g_cache_size_map.erase(this);
345 else g_cache_size_map[this] = bytes;
346
347 size_t maxCacheSize = getMaxCacheSize();
348 resizeTessellationCache(maxCacheSize);
349#endif
350 }
351
352 void Device::initTaskingSystem(size_t numThreads)
353 {
354 Lock<MutexSys> lock(g_mutex);
355 if (numThreads == 0)
356 g_num_threads_map[this] = std::numeric_limits<size_t>::max();
357 else
358 g_num_threads_map[this] = numThreads;
359
360 /* create task scheduler */
361 size_t maxNumThreads = getMaxNumThreads();
362 TaskScheduler::create(numThreads: maxNumThreads,set_affinity: State::set_affinity,start_threads: State::start_threads);
363#if USE_TASK_ARENA
364 const size_t nThreads = min(maxNumThreads,TaskScheduler::threadCount());
365 const size_t uThreads = min(max(numUserThreads,(size_t)1),nThreads);
366 arena = make_unique(new tbb::task_arena((int)nThreads,(unsigned int)uThreads));
367#endif
368 }
369
370 void Device::exitTaskingSystem()
371 {
372 Lock<MutexSys> lock(g_mutex);
373 g_num_threads_map.erase(x: this);
374
375 /* terminate tasking system */
376 if (g_num_threads_map.size() == 0) {
377 TaskScheduler::destroy();
378 }
379 /* or configure new number of threads */
380 else {
381 size_t maxNumThreads = getMaxNumThreads();
382 TaskScheduler::create(numThreads: maxNumThreads,set_affinity: State::set_affinity,start_threads: State::start_threads);
383 }
384#if USE_TASK_ARENA
385 arena.reset();
386#endif
387 }
388
389 void Device::setProperty(const RTCDeviceProperty prop, ssize_t val)
390 {
391 /* hidden internal properties */
392 switch ((size_t)prop)
393 {
394 case 1000000: debug_int0 = val; return;
395 case 1000001: debug_int1 = val; return;
396 case 1000002: debug_int2 = val; return;
397 case 1000003: debug_int3 = val; return;
398 }
399
400 throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown writable property");
401 }
402
403 ssize_t Device::getProperty(const RTCDeviceProperty prop)
404 {
405 size_t iprop = (size_t)prop;
406
407 /* get name of internal regression test */
408 if (iprop >= 2000000 && iprop < 3000000)
409 {
410 RegressionTest* test = getRegressionTest(index: iprop-2000000);
411 if (test) return (ssize_t) test->name.c_str();
412 else return 0;
413 }
414
415 /* run internal regression test */
416 if (iprop >= 3000000 && iprop < 4000000)
417 {
418 RegressionTest* test = getRegressionTest(index: iprop-3000000);
419 if (test) return test->run();
420 else return 0;
421 }
422
423 /* documented properties */
424 switch (prop)
425 {
426 case RTC_DEVICE_PROPERTY_VERSION_MAJOR: return RTC_VERSION_MAJOR;
427 case RTC_DEVICE_PROPERTY_VERSION_MINOR: return RTC_VERSION_MINOR;
428 case RTC_DEVICE_PROPERTY_VERSION_PATCH: return RTC_VERSION_PATCH;
429 case RTC_DEVICE_PROPERTY_VERSION : return RTC_VERSION;
430
431#if defined(EMBREE_TARGET_SIMD4) && defined(EMBREE_RAY_PACKETS)
432 case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return hasISA(SSE2);
433#else
434 case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return 0;
435#endif
436
437#if defined(EMBREE_TARGET_SIMD8) && defined(EMBREE_RAY_PACKETS)
438 case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return hasISA(AVX);
439#else
440 case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return 0;
441#endif
442
443#if defined(EMBREE_TARGET_SIMD16) && defined(EMBREE_RAY_PACKETS)
444 case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return hasISA(AVX512);
445#else
446 case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return 0;
447#endif
448
449#if defined(EMBREE_RAY_PACKETS)
450 case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 1;
451#else
452 case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 0;
453#endif
454
455#if defined(EMBREE_RAY_MASK)
456 case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 1;
457#else
458 case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 0;
459#endif
460
461#if defined(EMBREE_BACKFACE_CULLING)
462 case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 1;
463#else
464 case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 0;
465#endif
466
467#if defined(EMBREE_BACKFACE_CULLING_CURVES)
468 case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 1;
469#else
470 case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
471#endif
472
473#if defined(EMBREE_COMPACT_POLYS)
474 case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
475#else
476 case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 0;
477#endif
478
479#if defined(EMBREE_FILTER_FUNCTION)
480 case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 1;
481#else
482 case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 0;
483#endif
484
485#if defined(EMBREE_IGNORE_INVALID_RAYS)
486 case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 1;
487#else
488 case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 0;
489#endif
490
491#if defined(TASKING_INTERNAL)
492 case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 0;
493#endif
494
495#if defined(TASKING_TBB)
496 case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 1;
497#endif
498
499#if defined(TASKING_PPL)
500 case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 2;
501#endif
502
503#if defined(EMBREE_GEOMETRY_TRIANGLE)
504 case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 1;
505#else
506 case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 0;
507#endif
508
509#if defined(EMBREE_GEOMETRY_QUAD)
510 case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 1;
511#else
512 case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 0;
513#endif
514
515#if defined(EMBREE_GEOMETRY_CURVE)
516 case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 1;
517#else
518 case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 0;
519#endif
520
521#if defined(EMBREE_GEOMETRY_SUBDIVISION)
522 case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 1;
523#else
524 case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 0;
525#endif
526
527#if defined(EMBREE_GEOMETRY_USER)
528 case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 1;
529#else
530 case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 0;
531#endif
532
533#if defined(EMBREE_GEOMETRY_POINT)
534 case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 1;
535#else
536 case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 0;
537#endif
538
539#if defined(TASKING_PPL)
540 case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
541#elif defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
542 case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
543#else
544 case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 1;
545#endif
546
547#if defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION
548 case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 1;
549#else
550 case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 0;
551#endif
552
553 default: throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown readable property"); break;
554 };
555 }
556}
557

source code of qtquick3d/src/3rdparty/embree/kernels/common/device.cpp