1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #pragma once |
5 | |
6 | #include "default.h" |
7 | #include "device.h" |
8 | #include "builder.h" |
9 | #include "../../common/algorithms/parallel_any_of.h" |
10 | #include "scene_triangle_mesh.h" |
11 | #include "scene_quad_mesh.h" |
12 | #include "scene_user_geometry.h" |
13 | #include "scene_instance.h" |
14 | #include "scene_curves.h" |
15 | #include "scene_line_segments.h" |
16 | #include "scene_subdiv_mesh.h" |
17 | #include "scene_grid_mesh.h" |
18 | #include "scene_points.h" |
19 | #include "../subdiv/tessellation_cache.h" |
20 | |
21 | #include "acceln.h" |
22 | #include "geometry.h" |
23 | |
24 | namespace embree |
25 | { |
26 | /*! Base class all scenes are derived from */ |
27 | class Scene : public AccelN |
28 | { |
29 | ALIGNED_CLASS_(std::alignment_of<Scene>::value); |
30 | |
31 | public: |
32 | template<typename Ty, bool mblur = false> |
33 | class Iterator |
34 | { |
35 | public: |
36 | Iterator () {} |
37 | |
38 | Iterator (Scene* scene, bool all = false) |
39 | : scene(scene), all(all) {} |
40 | |
41 | __forceinline Ty* at(const size_t i) |
42 | { |
43 | Geometry* geom = scene->geometries[i].ptr; |
44 | if (geom == nullptr) return nullptr; |
45 | if (!all && !geom->isEnabled()) return nullptr; |
46 | const size_t mask = geom->getTypeMask() & Ty::geom_type; |
47 | if (!(mask)) return nullptr; |
48 | if ((geom->numTimeSteps != 1) != mblur) return nullptr; |
49 | return (Ty*) geom; |
50 | } |
51 | |
52 | __forceinline Ty* operator[] (const size_t i) { |
53 | return at(i); |
54 | } |
55 | |
56 | __forceinline size_t size() const { |
57 | return scene->size(); |
58 | } |
59 | |
60 | __forceinline size_t numPrimitives() const { |
61 | return scene->getNumPrimitives(Ty::geom_type,mblur); |
62 | } |
63 | |
64 | __forceinline size_t maxPrimitivesPerGeometry() |
65 | { |
66 | size_t ret = 0; |
67 | for (size_t i=0; i<scene->size(); i++) { |
68 | Ty* mesh = at(i); |
69 | if (mesh == nullptr) continue; |
70 | ret = max(ret,mesh->size()); |
71 | } |
72 | return ret; |
73 | } |
74 | |
75 | __forceinline unsigned int maxGeomID() |
76 | { |
77 | unsigned int ret = 0; |
78 | for (size_t i=0; i<scene->size(); i++) { |
79 | Ty* mesh = at(i); |
80 | if (mesh == nullptr) continue; |
81 | ret = max(ret,(unsigned int)i); |
82 | } |
83 | return ret; |
84 | } |
85 | |
86 | __forceinline unsigned maxTimeStepsPerGeometry() |
87 | { |
88 | unsigned ret = 0; |
89 | for (size_t i=0; i<scene->size(); i++) { |
90 | Ty* mesh = at(i); |
91 | if (mesh == nullptr) continue; |
92 | ret = max(ret,mesh->numTimeSteps); |
93 | } |
94 | return ret; |
95 | } |
96 | |
97 | private: |
98 | Scene* scene; |
99 | bool all; |
100 | }; |
101 | |
102 | class Iterator2 |
103 | { |
104 | public: |
105 | Iterator2 () {} |
106 | |
107 | Iterator2 (Scene* scene, Geometry::GTypeMask typemask, bool mblur) |
108 | : scene(scene), typemask(typemask), mblur(mblur) {} |
109 | |
110 | __forceinline Geometry* at(const size_t i) |
111 | { |
112 | Geometry* geom = scene->geometries[i].ptr; |
113 | if (geom == nullptr) return nullptr; |
114 | if (!geom->isEnabled()) return nullptr; |
115 | if (!(geom->getTypeMask() & typemask)) return nullptr; |
116 | if ((geom->numTimeSteps != 1) != mblur) return nullptr; |
117 | return geom; |
118 | } |
119 | |
120 | __forceinline Geometry* operator[] (const size_t i) { |
121 | return at(i); |
122 | } |
123 | |
124 | __forceinline size_t size() const { |
125 | return scene->size(); |
126 | } |
127 | |
128 | private: |
129 | Scene* scene; |
130 | Geometry::GTypeMask typemask; |
131 | bool mblur; |
132 | }; |
133 | |
134 | public: |
135 | |
136 | /*! Scene construction */ |
137 | Scene (Device* device); |
138 | |
139 | /*! Scene destruction */ |
140 | ~Scene () noexcept; |
141 | |
142 | private: |
143 | /*! class is non-copyable */ |
144 | Scene (const Scene& other) DELETED; // do not implement |
145 | Scene& operator= (const Scene& other) DELETED; // do not implement |
146 | |
147 | public: |
148 | void createTriangleAccel(); |
149 | void createTriangleMBAccel(); |
150 | void createQuadAccel(); |
151 | void createQuadMBAccel(); |
152 | void createHairAccel(); |
153 | void createHairMBAccel(); |
154 | void createSubdivAccel(); |
155 | void createSubdivMBAccel(); |
156 | void createUserGeometryAccel(); |
157 | void createUserGeometryMBAccel(); |
158 | void createInstanceAccel(); |
159 | void createInstanceMBAccel(); |
160 | void createInstanceExpensiveAccel(); |
161 | void createInstanceExpensiveMBAccel(); |
162 | void createGridAccel(); |
163 | void createGridMBAccel(); |
164 | |
165 | /*! prints statistics about the scene */ |
166 | void printStatistics(); |
167 | |
168 | /*! clears the scene */ |
169 | void clear(); |
170 | |
171 | /*! detaches some geometry */ |
172 | void detachGeometry(size_t geomID); |
173 | |
174 | void setBuildQuality(RTCBuildQuality quality_flags); |
175 | RTCBuildQuality getBuildQuality() const; |
176 | |
177 | void setSceneFlags(RTCSceneFlags scene_flags); |
178 | RTCSceneFlags getSceneFlags() const; |
179 | |
180 | void commit (bool join); |
181 | void commit_task (); |
182 | void build () {} |
183 | |
184 | void updateInterface(); |
185 | |
186 | /* return number of geometries */ |
187 | __forceinline size_t size() const { return geometries.size(); } |
188 | |
189 | /* bind geometry to the scene */ |
190 | unsigned int bind (unsigned geomID, Ref<Geometry> geometry); |
191 | |
192 | /* determines if scene is modified */ |
193 | __forceinline bool isModified() const { return modified; } |
194 | |
195 | /* sets modified flag */ |
196 | __forceinline void setModified(bool f = true) { |
197 | modified = f; |
198 | } |
199 | |
200 | __forceinline bool isGeometryModified(size_t geomID) |
201 | { |
202 | Ref<Geometry>& g = geometries[geomID]; |
203 | if (!g) return false; |
204 | return g->getModCounter() > geometryModCounters_[geomID]; |
205 | } |
206 | |
207 | protected: |
208 | |
209 | __forceinline void checkIfModifiedAndSet () |
210 | { |
211 | if (isModified ()) return; |
212 | |
213 | auto geometryIsModified = [this](size_t geomID)->bool { |
214 | return isGeometryModified(geomID); |
215 | }; |
216 | |
217 | if (parallel_any_of (size_t(0), geometries.size (), geometryIsModified)) { |
218 | setModified (); |
219 | } |
220 | } |
221 | |
222 | public: |
223 | |
224 | /* get mesh by ID */ |
225 | __forceinline Geometry* get(size_t i) { assert(i < geometries.size()); return geometries[i].ptr; } |
226 | __forceinline const Geometry* get(size_t i) const { assert(i < geometries.size()); return geometries[i].ptr; } |
227 | |
228 | template<typename Mesh> |
229 | __forceinline Mesh* get(size_t i) { |
230 | assert(i < geometries.size()); |
231 | assert(geometries[i]->getTypeMask() & Mesh::geom_type); |
232 | return (Mesh*)geometries[i].ptr; |
233 | } |
234 | template<typename Mesh> |
235 | __forceinline const Mesh* get(size_t i) const { |
236 | assert(i < geometries.size()); |
237 | assert(geometries[i]->getTypeMask() & Mesh::geom_type); |
238 | return (Mesh*)geometries[i].ptr; |
239 | } |
240 | |
241 | template<typename Mesh> |
242 | __forceinline Mesh* getSafe(size_t i) { |
243 | assert(i < geometries.size()); |
244 | if (geometries[i] == null) return nullptr; |
245 | if (!(geometries[i]->getTypeMask() & Mesh::geom_type)) return nullptr; |
246 | else return (Mesh*) geometries[i].ptr; |
247 | } |
248 | |
249 | __forceinline Ref<Geometry> get_locked(size_t i) { |
250 | Lock<SpinLock> lock(geometriesMutex); |
251 | assert(i < geometries.size()); |
252 | return geometries[i]; |
253 | } |
254 | |
255 | /* flag decoding */ |
256 | __forceinline bool isFastAccel() const { return !isCompactAccel() && !isRobustAccel(); } |
257 | __forceinline bool isCompactAccel() const { return scene_flags & RTC_SCENE_FLAG_COMPACT; } |
258 | __forceinline bool isRobustAccel() const { return scene_flags & RTC_SCENE_FLAG_ROBUST; } |
259 | __forceinline bool isStaticAccel() const { return !(scene_flags & RTC_SCENE_FLAG_DYNAMIC); } |
260 | __forceinline bool isDynamicAccel() const { return scene_flags & RTC_SCENE_FLAG_DYNAMIC; } |
261 | |
262 | __forceinline bool hasContextFilterFunction() const { |
263 | return scene_flags & RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION; |
264 | } |
265 | |
266 | __forceinline bool hasGeometryFilterFunction() { |
267 | return world.numFilterFunctions != 0; |
268 | } |
269 | |
270 | __forceinline bool hasFilterFunction() { |
271 | return hasContextFilterFunction() || hasGeometryFilterFunction(); |
272 | } |
273 | |
274 | /* test if scene got already build */ |
275 | __forceinline bool isBuild() const { return is_build; } |
276 | |
277 | public: |
278 | IDPool<unsigned,0xFFFFFFFE> id_pool; |
279 | vector<Ref<Geometry>> geometries; //!< list of all user geometries |
280 | vector<unsigned int> geometryModCounters_; |
281 | vector<float*> vertices; |
282 | |
283 | public: |
284 | Device* device; |
285 | |
286 | /* these are to detect if we need to recreate the acceleration structures */ |
287 | bool flags_modified; |
288 | unsigned int enabled_geometry_types; |
289 | |
290 | RTCSceneFlags scene_flags; |
291 | RTCBuildQuality quality_flags; |
292 | MutexSys buildMutex; |
293 | SpinLock geometriesMutex; |
294 | bool is_build; |
295 | private: |
296 | bool modified; //!< true if scene got modified |
297 | |
298 | public: |
299 | |
300 | /*! global lock step task scheduler */ |
301 | #if defined(TASKING_INTERNAL) |
302 | MutexSys schedulerMutex; |
303 | Ref<TaskScheduler> scheduler; |
304 | #elif defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION |
305 | tbb::isolated_task_group group; |
306 | #elif defined(TASKING_TBB) |
307 | tbb::task_group group; |
308 | #elif defined(TASKING_PPL) |
309 | concurrency::task_group group; |
310 | #endif |
311 | |
312 | public: |
313 | struct BuildProgressMonitorInterface : public BuildProgressMonitor { |
314 | BuildProgressMonitorInterface(Scene* scene) |
315 | : scene(scene) {} |
316 | void operator() (size_t dn) const { scene->progressMonitor(double(dn)); } |
317 | private: |
318 | Scene* scene; |
319 | }; |
320 | BuildProgressMonitorInterface progressInterface; |
321 | RTCProgressMonitorFunction progress_monitor_function; |
322 | void* progress_monitor_ptr; |
323 | std::atomic<size_t> progress_monitor_counter; |
324 | void progressMonitor(double nprims); |
325 | void setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr); |
326 | |
327 | private: |
328 | GeometryCounts world; //!< counts for geometry |
329 | |
330 | public: |
331 | |
332 | __forceinline size_t numPrimitives() const { |
333 | return world.size(); |
334 | } |
335 | |
336 | __forceinline size_t getNumPrimitives(Geometry::GTypeMask mask, bool mblur) const |
337 | { |
338 | size_t count = 0; |
339 | |
340 | if (mask & Geometry::MTY_TRIANGLE_MESH) |
341 | count += mblur ? world.numMBTriangles : world.numTriangles; |
342 | |
343 | if (mask & Geometry::MTY_QUAD_MESH) |
344 | count += mblur ? world.numMBQuads : world.numQuads; |
345 | |
346 | if (mask & Geometry::MTY_CURVE2) |
347 | count += mblur ? world.numMBLineSegments : world.numLineSegments; |
348 | |
349 | if (mask & Geometry::MTY_CURVE4) |
350 | count += mblur ? world.numMBBezierCurves : world.numBezierCurves; |
351 | |
352 | if (mask & Geometry::MTY_POINTS) |
353 | count += mblur ? world.numMBPoints : world.numPoints; |
354 | |
355 | if (mask & Geometry::MTY_SUBDIV_MESH) |
356 | count += mblur ? world.numMBSubdivPatches : world.numSubdivPatches; |
357 | |
358 | if (mask & Geometry::MTY_USER_GEOMETRY) |
359 | count += mblur ? world.numMBUserGeometries : world.numUserGeometries; |
360 | |
361 | if (mask & Geometry::MTY_INSTANCE_CHEAP) |
362 | count += mblur ? world.numMBInstancesCheap : world.numInstancesCheap; |
363 | |
364 | if (mask & Geometry::MTY_INSTANCE_EXPENSIVE) |
365 | count += mblur ? world.numMBInstancesExpensive : world.numInstancesExpensive; |
366 | |
367 | if (mask & Geometry::MTY_GRID_MESH) |
368 | count += mblur ? world.numMBGrids : world.numGrids; |
369 | |
370 | return count; |
371 | } |
372 | |
373 | template<typename Mesh, bool mblur> |
374 | __forceinline unsigned getNumTimeSteps() |
375 | { |
376 | if (!mblur) |
377 | return 1; |
378 | |
379 | Scene::Iterator<Mesh,mblur> iter(this); |
380 | return iter.maxTimeStepsPerGeometry(); |
381 | } |
382 | |
383 | template<typename Mesh, bool mblur> |
384 | __forceinline unsigned int getMaxGeomID() |
385 | { |
386 | Scene::Iterator<Mesh,mblur> iter(this); |
387 | return iter.maxGeomID(); |
388 | } |
389 | }; |
390 | } |
391 | |