All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
USD_ThreadedTraverse.h
1 //
2 // Copyright 2017 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef _GUSD_THREADEDTRAVERSE_H_
25 #define _GUSD_THREADEDTRAVERSE_H_
26 
27 
28 #include <UT/UT_Array.h>
29 #include <UT/UT_Interrupt.h>
30 #include <UT/UT_ParallelUtil.h>
31 #include <UT/UT_Task.h>
32 #include <UT/UT_ThreadSpecificValue.h>
33 
34 #include "gusd/UT_Assert.h"
35 #include "gusd/USD_Traverse.h"
36 #include "gusd/USD_Utils.h"
37 
38 #include "pxr/pxr.h"
39 #include "pxr/base/arch/hints.h"
40 #include "pxr/usd/usd/prim.h"
41 #include "pxr/usd/usdGeom/imageable.h"
42 
43 PXR_NAMESPACE_OPEN_SCOPE
44 
45 namespace GusdUSD_ThreadedTraverse {
46 
47 
48 template <class Visitor>
49 bool ParallelFindPrims(const UsdPrim& root,
50  UsdTimeCode time,
51  GusdPurposeSet purposes,
52  UT_Array<UsdPrim>& prims,
53  const Visitor& visitor,
54  bool skipRoot=true);
55 
56 template <class Visitor>
57 bool ParallelFindPrims(const UT_Array<UsdPrim>& roots,
58  const GusdDefaultArray<UsdTimeCode>& times,
59  const GusdDefaultArray<GusdPurposeSet>& purposes,
60  UT_Array<GusdUSD_Traverse::PrimIndexPair>& prims,
61  const Visitor& visitor,
62  bool skipRoot=true);
63 
64 
68 template <class Visitor, bool Recursive=false>
70 {
71  bool AcceptPrim(const UsdPrim& prim,
72  UsdTimeCode time,
73  GusdPurposeSet purposes,
74  GusdUSD_TraverseControl& ctl) const;
75 
76  Usd_PrimFlagsPredicate TraversalPredicate() const
79 };
80 
81 
82 template <class Visitor, bool Recursive>
83 bool
85  const UsdPrim& prim,
86  UsdTimeCode time,
87  GusdPurposeSet purposes,
88  GusdUSD_TraverseControl& ctl) const
89 {
90  UsdGeomImageable ip(prim);
91  if(ip) {
92  TfToken purpose;
93  ip.GetPurposeAttr().Get(&purpose);
94  if( GusdPurposeInSet( purpose, purposes )) {
95  if(ARCH_UNLIKELY(Visitor()(prim, time, ctl))) {
96  if(!Recursive)
97  ctl.PruneChildren();
98  return true;
99  }
100  } else {
101  ctl.PruneChildren();
102  }
103  } else {
104  ctl.PruneChildren();
105  }
106  return false;
107 }
108 
109 
110 struct TaskThreadData
111 {
112  UT_Array<GusdUSD_Traverse::PrimIndexPair> prims;
113 };
114 
115 typedef UT_ThreadSpecificValue<TaskThreadData*> TaskThreadDataTLS;
116 
117 
118 struct TaskData
119 {
120  ~TaskData();
121 
122  TaskThreadDataTLS threadData;
123 
126  bool GatherPrimsFromThreads(UT_Array<UsdPrim>& prims);
127 
128  bool GatherPrimsFromThreads(
129  UT_Array<GusdUSD_Traverse::PrimIndexPair>& prims);
130 };
131 
132 
137 template <class Visitor>
138 struct TraverseTaskT : public UT_Task
139 {
140  TraverseTaskT(const UsdPrim& prim, exint idx, UsdTimeCode time,
141  GusdPurposeSet purposes,
142  TaskData& data, const Visitor& visitor, bool skipPrim)
143  : UT_Task(), _prim(prim), _idx(idx), _time(time),
144  _purposes(purposes), _data(data),
145  _visited(false), _visitor(visitor), _skipPrim(skipPrim) {}
146 
147  virtual UT_Task* run();
148 
149 private:
150  UsdPrim _prim;
151  exint _idx;
152  UsdTimeCode _time;
153  GusdPurposeSet _purposes;
154  TaskData& _data;
155  bool _visited;
156  Visitor _visitor;
157  bool _skipPrim;
158 };
159 
160 
164 template <class Visitor>
165 UT_Task*
167 {
168  /* XXX: Ended up needing this check at some point.
169  Find out if it's still necessary.*/
170  if(ARCH_UNLIKELY(_visited)) return NULL;
171  _visited = true;
172 
173  UT_ASSERT_P(_prim);
174 
175  if(!_skipPrim) {
176 
178  if(ARCH_UNLIKELY(_visitor.AcceptPrim(_prim, _time, _purposes, ctl))) {
179  /* Matched. Add it to the thread-specific list.*/
180  auto*& threadData = _data.threadData.get();
181  if(!threadData)
182  threadData = new TaskThreadData;
183  threadData->prims.append(
184  GusdUSD_Traverse::PrimIndexPair(_prim, _idx));
185  }
186  if(ARCH_UNLIKELY(!ctl.GetVisitChildren())) {
187  return NULL;
188  }
189  }
190 
191  /* Count the children so we can increment the ref count accordingly.*/
192  int count = 0;
193  auto children = _prim.GetFilteredChildren(_visitor.TraversalPredicate());
194  for (auto i = children.begin(); i != children.end(); ++i, ++count) {}
195 
196  if(count == 0)
197  return NULL;
198 
199  setRefCount(count);
200  recycleAsContinuation();
201 
202  const int last = count - 1;
203  int idx = 0;
204  for (const auto& child :
205  _prim.GetFilteredChildren(_visitor.TraversalPredicate())) {
206  auto& task =
207  *new(allocate_child()) TraverseTaskT(child, _idx, _time,
208  _purposes, _data,
209  _visitor, /*skip prim*/ false);
210  if(idx == last)
211  return &task;
212  else
213  spawnChild(task);
214  ++idx;
215  }
216  return NULL;
217 }
218 
219 
220 template <class Visitor>
221 bool
222 ParallelFindPrims(const UsdPrim& root,
223  UsdTimeCode time,
224  GusdPurposeSet purposes,
225  UT_Array<UsdPrim>& prims,
226  const Visitor& visitor,
227  bool skipRoot)
228 {
229  TaskData data;
230  bool skipPrim = skipRoot || root.GetPath() == SdfPath::AbsoluteRootPath();
231  auto& task =
232  *new(UT_Task::allocate_root())
233  TraverseTaskT<Visitor>(root, -1, time, purposes,
234  data, visitor, skipPrim);
235  UT_Task::spawnRootAndWait(task);
236 
237  if(UTgetInterrupt()->opInterrupt())
238  return false;
239 
240  return data.GatherPrimsFromThreads(prims);
241 }
242 
243 
244 template <class Visitor>
245 struct RunTasksT
246 {
247  RunTasksT(const UT_Array<UsdPrim>& roots,
248  const GusdDefaultArray<UsdTimeCode>& times,
249  const GusdDefaultArray<GusdPurposeSet>& purposes,
250  const Visitor& visitor, TaskData& data, bool skipRoot)
251  : _roots(roots), _times(times), _purposes(purposes),
252  _visitor(visitor), _data(data), _skipRoot(skipRoot) {}
253 
254  void operator()(const UT_BlockedRange<std::size_t>& r) const
255  {
256  auto* boss = GusdUTverify_ptr(UTgetInterrupt());
257 
258  for(std::size_t i = r.begin(); i < r.end(); ++i)
259  {
260  if(boss->opInterrupt())
261  return;
262 
263  if(const UsdPrim& prim = _roots(i)) {
264  bool skipPrim = _skipRoot ||
266 
267  auto& task =
268  *new(UT_Task::allocate_root())
269  TraverseTaskT<Visitor>(prim, i, _times(i),
270  _purposes(i), _data,
271  _visitor, skipPrim);
272  UT_Task::spawnRootAndWait(task);
273  }
274  }
275  }
276 
277 private:
278  const UT_Array<UsdPrim>& _roots;
279  const GusdDefaultArray<UsdTimeCode>& _times;
280  const GusdDefaultArray<GusdPurposeSet>& _purposes;
281  const Visitor& _visitor;
282  TaskData& _data;
283  const bool _skipRoot;
284 };
285 
286 
287 
288 
289 template <class Visitor>
290 bool
291 ParallelFindPrims(const UT_Array<UsdPrim>& roots,
292  const GusdDefaultArray<UsdTimeCode>& times,
293  const GusdDefaultArray<GusdPurposeSet>& purposes,
294  UT_Array<GusdUSD_Traverse::PrimIndexPair>& prims,
295  const Visitor& visitor,
296  bool skipRoot)
297 {
298  TaskData data;
299  UTparallelFor(UT_BlockedRange<std::size_t>(0, roots.size()),
300  RunTasksT<Visitor>(roots, times, purposes,
301  visitor, data, skipRoot));
302  if(UTgetInterrupt()->opInterrupt())
303  return false;
304 
305  return data.GatherPrimsFromThreads(prims);
306 }
307 
308 
309 } /*namespace GusdUSD_ThreadedTraverse*/
310 
311 PXR_NAMESPACE_CLOSE_SCOPE
312 
313 #endif /*_GUSD_THREADEDTRAVERSE_H_*/
SdfPath GetPath() const
Return the complete scene path to this object on its UsdStage, which may (UsdPrim) or may not (all ot...
Definition: object.h:193
unspecified UsdPrimIsAbstract
Tests UsdPrim::IsAbstract()
Helper to provide control over traversal through children.
Definition: USD_Traverse.h:135
unspecified UsdPrimIsActive
Tests UsdPrim::IsActive()
unspecified UsdPrimIsLoaded
Tests UsdPrim::IsLoaded()
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:89
Represent a time value, which may be either numeric, holding a double value, or a sentinel value UsdT...
Definition: timeCode.h:85
unspecified UsdPrimIsDefined
Tests UsdPrim::IsDefined()
Methods for USD scene traversal.
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a &quot;Prim&quot; as ...
Definition: prim.h:131
Usd_PrimFlagsPredicate UsdTraverseInstanceProxies(Usd_PrimFlagsPredicate predicate)
This function is used to allow the prim traversal functions listed under Prim predicate flags to trav...
Definition: primFlags.h:577
Task for traversing a prim tree in parallel.
static SDF_API const SdfPath & AbsoluteRootPath()
The absolute path representing the top of the namespace hierarchy.
virtual UT_Task * run()
XXX: This parallel recursion pattern follows the &#39;Recycling Parent as Continuation&#39; pattern from TBB&#39;...
Base class for all prims that may require rendering or visualization of some sort.
Definition: imageable.h:74