HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DEP_MicroNode.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: DEP_MicroNode.h (DEP Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __DEP_MICRONODE_H_INCLUDED__
12 #define __DEP_MICRONODE_H_INCLUDED__
13 
14 #include "DEP_API.h"
15 #include "DEP_ContextOptions.h"
16 #include <UT/UT_Array.h>
17 #include <UT/UT_ArraySet.h>
18 #include <UT/UT_ConcurrentVector.h>
19 #include <UT/UT_Function.h>
20 #include <UT/UT_IntArray.h>
21 #include <UT/UT_NonCopyable.h>
22 #include <UT/UT_SmallObject.h>
23 #include <UT/UT_StringHolder.h>
24 #include <UT/UT_TBBSpinLock.h>
25 #include <UT/UT_ValArray.h>
26 #include <SYS/SYS_Inline.h>
27 #include <SYS/SYS_Math.h>
28 #include <SYS/SYS_Types.h>
29 #include <iosfwd>
30 
32 
34 
35 /// Propagation info for a dep micro node
37 {
38 public:
39  DEP_PropagateData() { myExprChange = false; }
40  ~DEP_PropagateData() = default;
41 
43 
44  void setExprChange(bool expr_change)
45  { myExprChange = expr_change; }
46  bool isExprChange() const
47  { return myExprChange; }
48 
49 protected:
50  bool myExprChange:1; // a parm expr modification?
51 };
52 
53 /// Represent an atomic unit of computation for dependency tracking.
54 ///
55 /// DEP_MicroNode's form a dependency graph that are connected both implicitly
56 /// and explicitly. The base class maintains the explicit edges while
57 /// subclasses maintain the implicit edges by overriding the
58 /// getInputs()/getOutputs() methods.
59 ///
60 class DEP_API DEP_MicroNode : public UT_SmallObject<DEP_MicroNode>
61 {
62 public:
63  DEP_MicroNode();
64  virtual ~DEP_MicroNode();
65 
67 
68  virtual const char * className() const
69  { return "DEP_MicroNode"; }
70 
71  /// Get list of all our non-null inputs, both implicit and explicit.
72  /// The base class returns the list of explicit inputs.
73  virtual void getInputs(DEP_MicroNodeList &inputs) const;
74 
75  /// Clear all inputs, including any state data related to them. Default
76  /// implementation just calls clearExplicitInputs() and
77  /// setTimeDependent(false).
78  virtual void clearInputs();
79 
80  /// Get list of all our non-null outputs, both implicit and explicit.
81  /// The base class returns the list of explicit outputs.
82  virtual void getOutputs(DEP_MicroNodeList &outputs) const;
83 
84  /// update() is used by users of micro-nodes to mark this node as clean at
85  /// the given time t. By default, it simply marks it as no longer dirty but
86  /// subclasses override this to do more work.
87  virtual void update(fpreal t)
88  { setDirty(false); }
89 
90  /// requiresUpdate() specifies if the micro-node was dirtied, possibly
91  /// based on the time t. By default, it returns isDirty() but subclasses
92  /// override this to handle other conditions that make this micro-node
93  /// requiring an update.
94  virtual bool requiresUpdate(fpreal t) const
95  { return isDirty(); }
96 
97  /// Methods for manipulating explicit edges
98  // @{
99 
100  /// Add an input that this micronode depends on, with control on whether to
101  /// check for duplicates.
102  void addExplicitInput(
103  DEP_MicroNode &inp,
104  bool check_dup);
105 
106  /// Add an input that this micronode depends on
108  { addExplicitInput(inp, /*check_dup*/true); }
109 
110  /// Bulk add multiple explicit inputs at once
111  void addExplicitInputs(
112  const DEP_MicroNodeList &sources,
113  bool check_dup = true);
114 
115  /// Get list of all non-null explicit inputs
116  void getExplicitInputs(
117  DEP_MicroNodeList &inputs) const;
118 
119  /// Checks if a particular explicit input is already in our list.
120  bool hasExplicitInput(
121  DEP_MicroNode &inp) const;
122 
123  /// Get the number of non-null inputs
125  { return countEdges(myExplicitInputs); }
126 
127  /// Get list of all non-null explicit outputs
128  void getExplicitOutputs(
129  DEP_MicroNodeList &outputs) const;
130 
131  /// Get the number of non-null outputs
133  { return countEdges(myExplicitOutputs); }
134 
135  // @}
136 
137  typedef UT_Function<
138  void (DEP_MicroNode & /*micronode*/,
139  DEP_MicroNode & /*src*/)
141  typedef UT_Function<
142  bool (const DEP_MicroNode & /*micronode*/,
143  const DEP_MicroNode & /*src*/)
145 
146  /// Mark this micronode and all its dependents as dirty. The global dirty
147  /// counter will be incremented once for each call to propagateDirty().
148  ///
149  /// @param client_visit Called for each micronode that is dirtied
150  /// @param only_outputs If true, then *this is ommitted from being
151  /// dirtied
152  ///
153  /// @note This method is NOT thread-safe with *any* operation on *any*
154  /// micronode. Only call this when no other micronode operations are
155  /// running.
156  void propagateDirty(
157  const Visitor &client_visit,
158  bool only_outputs = false);
159 
160  /// Callbacks for what to do when the micronode becomes dirty.
161  /// Derived micronodes can override this. Note that it requires
162  /// knowledge of who made it dirty as they may behave differently.
163  /// Currently used by OP_Node::propagateDirtyMicroNode
165  const DEP_PropagateData &propdata)
166  { }
167 
168 
169  /// Traverse all ancestor inputs of this micronode
170  void traverseAncestorInputs(
171  const TraverseVisitor &visitor) const;
172 
173  /// Mark this micronode as having seen the given global dirty counter.
174  /// Returns false if we've already seen it.
175  bool markVisitPass(int pass)
176  {
177  if (myLastVisitPass == pass)
178  return false;
179  myLastVisitPass = pass;
180  return true;
181  }
182 
184  int lastVisitPass() const
185  { return myLastVisitPass; }
186 
187  /// Obtain approximate memory usage
188  virtual int64 getMemoryUsage(bool inclusive) const;
189 
190  /// Dump contents to output stream, strictly for debugging purposes
191  virtual void dump(
192  std::ostream &os,
193  const char *prefix = nullptr,
194  int indent_level = 0) const;
195  /// Dump the contents is a manner more suitable for DOT.
196  void dumpAsDOT(
197  std::ostream &os,
198  const char *prefix = nullptr,
199  int indent_level = 0) const;
200 
201  /// Set time dependent flag if any explicit inputs are set.
202  /// Returns true if any explicit inputs are true.
203  bool inheritTimeDependentFromExplicitInputs();
204 
205  /// Set time interested flag if any explicit inputs are set.
206  /// Returns true if any explicit inputs are true.
207  bool inheritTimeInterestedFromExplicitInputs();
208 
209  /// Inherit extra dependencies from all explicit inputs.
210  /// The ignore_deps string array MUST BE SORTED.
211  /// Returns true if any extra dependencies are found.
212  bool inheritContextOptionDepsFromExplicitInputs(
213  const UT_StringArray &ignore_deps);
214 
215  /// Flag accessors
216  // @{
218  bool isDirty() const
219  { return myDirty; }
220  void setDirty(bool flag, bool allow_clear=true)
221  {
222  myDirty = flag;
223  if (allow_clear
224  && myDirty
225  && canClearDependencies())
226  {
227  clearInputs();
228  }
229  }
230 
232  bool isTimeDependent() const
233  { return myTimeDependent; }
235  void setTimeDependent(bool time_dependent)
236  { myTimeDependent = time_dependent; }
237 
239  bool isTimeInterested() const
240  { return myTimeInterested; }
242  void setTimeInterested(bool time_interested)
243  { myTimeInterested = time_interested; }
244 
246  bool hasContextOptionDeps() const
247  { return myContextOptionDeps &&
248  !myContextOptionDeps->empty(); }
252  myContextOptionDeps); }
255  const DEP_ContextOptionDeps &opts)
256  { if (opts.empty()) return;
258  myContextOptionDeps,
259  &myContextOptionDepsLock).insert(
260  opts.begin(), opts.end()); }
263  { if (!opt.isstring()) return;
265  myContextOptionDeps,
266  &myContextOptionDepsLock).
267  insert(opt); }
271  myContextOptionDepsLock);
272  myContextOptionDeps.reset(); }
273 
275  bool isOpDataMicroNode() const
276  { return myIsOPDataMicroNode; }
277 
278  // @}
279 
280  /// Global control whether dependencies can be cleared.
281  static SYS_FORCE_INLINE
283  { return (theKeepDependenciesCount == 0); }
284 
285  /// Global control whether we can evaluate exports
286  static SYS_FORCE_INLINE
288  { return (theBlockEvaluateExports == 0); }
289 
290  /// One true method to compare equality of time values for caching.
291  /// This particular form originates from what OP_Node::cook() did from the
292  /// dawn of time.
294  { return SYSequalZero(a - b); }
295 
296 protected:
297  /// These methods are overriden by subclasses to be used by the
298  /// dirty propagation algorithm.
299  /// @{
300 
301  /// Used to determine if a micronode is currently evaluating. If this
302  /// returns true, during dirty propagation, it will prevent dependencies
303  /// from being removed from it.
304  virtual bool isEvaluating() const
305  { return false; }
306 
307  /// evaluateExports() is called after isExporting() is noted to be true
308  /// during a dirty propagation pass initiated by dirtySubtree().
309  virtual void evaluateExports() { }
310 
311  /// Used to determine if a micronode requires its exports to be evaluated
312  /// during the propagation pass.
313  virtual bool isExporting() const
314  { return false; }
315 
316  /// @}
317 
319  void setIsOpDataMicroNode( bool b )
320  { myIsOPDataMicroNode = b; }
321 
322 private:
323  typedef UT_TBBSpinLock EdgeLock;
324  typedef UT_TBBSpinLock::Scope EdgeLockScope;
325 
326  typedef UT_Array<DEP_MicroNode *> MicroNodeInputPtrVector;
327  typedef UT_ConcurrentVector<DEP_MicroNode *> MicroNodeOutputPtrVector;
328  typedef UT_ArraySet<DEP_MicroNode*> MicroNodePtrSet;
329 
330  void clearExplicitInputs();
331  void clearExplicitOutputs();
332 
333  void compactExplicitInputsAndOutputs();
334 
335  static void compactVector(
336  MicroNodeOutputPtrVector &vec);
337  static void compactVector(
338  MicroNodeInputPtrVector &vec);
339 
340  template <typename MICRONODE_ARRAY>
341  static void getEdgeList(
342  const MICRONODE_ARRAY &edges,
343  DEP_MicroNodeList &micronodes);
344  template <typename MICRONODE_ARRAY>
345  static int countEdges(const MICRONODE_ARRAY &edges);
346 
347 private:
348 
349  /// The list of explicit edges for micronodes
350  // @{
351  EdgeLock myExplicitInputsLock;
352  MicroNodeInputPtrVector myExplicitInputs;
353  MicroNodePtrSet myExplicitInputsSet;
354  MicroNodeOutputPtrVector myExplicitOutputs;
355  // @}
356 
357  DEP_ContextOptionDepsLock myContextOptionDepsLock;
358  DEP_ContextOptionDepsPtr myContextOptionDeps;
359  int myLastVisitPass;
360 
361  bool myDirty;
362  bool myTimeDependent;
363  bool myTimeInterested;
364  bool myIsOPDataMicroNode;
365 
366  static int theKeepDependenciesCount;
367  static int theBlockEvaluateExports;
368 
369  friend class dep_Visitor;
372 };
373 
374 /// Global control whether dependencies can be cleared.
376 {
377 public:
379  { ++DEP_MicroNode::theKeepDependenciesCount; }
381  { --DEP_MicroNode::theKeepDependenciesCount; }
383 };
384 
385 /// Global control whether we can evaluate exports
387 {
388 public:
390  { ++DEP_MicroNode::theBlockEvaluateExports; }
392  { --DEP_MicroNode::theBlockEvaluateExports; }
394 };
395 
396 ///////////////////////////////////////////////////////////////////////////////
397 // Inline Implementations
398 //
399 
400 template <typename MICRONODE_ARRAY>
401 /* static */
402 int
403 DEP_MicroNode::countEdges(const MICRONODE_ARRAY &edges)
404 {
405  int count = 0;
406  for (DEP_MicroNode *e : edges)
407  {
408  if (e)
409  count++;
410  }
411  return count;
412 }
413 
414 #endif // __DEP_MICRONODE_H_INCLUDED__
SYS_FORCE_INLINE void setTimeDependent(bool time_dependent)
Flag accessors.
UT_UniquePtr< DEP_ContextOptionDeps > DEP_ContextOptionDepsPtr
virtual void becameDirty(DEP_MicroNode &src, const DEP_PropagateData &propdata)
static SYS_FORCE_INLINE bool isSameTime(fpreal a, fpreal b)
virtual void update(fpreal t)
Definition: DEP_MicroNode.h:87
void
Definition: png.h:1083
Global control whether dependencies can be cleared.
SYS_FORCE_INLINE bool isDirty() const
Flag accessors.
virtual bool requiresUpdate(fpreal t) const
Definition: DEP_MicroNode.h:94
DEP_API const DEP_ContextOptionDeps & DEPgetContextOptionDepsFromPtr(const DEP_ContextOptionDepsPtr &ptr)
SYS_FORCE_INLINE bool isTimeInterested() const
Flag accessors.
UT_ConcurrentSet< UT_StringHolder > DEP_ContextOptionDeps
UT_Array< DEP_MicroNode * > DEP_MicroNodeList
Definition: DEP_MicroNode.h:31
virtual bool isExporting() const
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
SYS_FORCE_INLINE const DEP_ContextOptionDeps & getContextOptionDeps() const
Flag accessors.
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3556
UT_Function< bool(const DEP_MicroNode &, const DEP_MicroNode &) > TraverseVisitor
OutGridT const XformOp bool bool
void setDirty(bool flag, bool allow_clear=true)
Flag accessors.
bool markVisitPass(int pass)
GLsizei GLenum * sources
Definition: glcorearb.h:2542
SYS_FORCE_INLINE void setIsOpDataMicroNode(bool b)
SYS_FORCE_INLINE int lastVisitPass() const
SYS_FORCE_INLINE void clearContextOptionDeps()
Flag accessors.
UT_Function< void(DEP_MicroNode &, DEP_MicroNode &) > Visitor
SYS_FORCE_INLINE int getNumExplicitInputs() const
Get the number of non-null inputs.
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
virtual bool isEvaluating() const
long long int64
Definition: SYS_Types.h:116
SYS_FORCE_INLINE bool isTimeDependent() const
Flag accessors.
SYS_FORCE_INLINE void addContextOptionDep(const UT_StringHolder &opt)
Flag accessors.
static SYS_FORCE_INLINE bool canClearDependencies()
Global control whether dependencies can be cleared.
Global control whether we can evaluate exports.
std::function< T > UT_Function
Definition: UT_Function.h:37
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
GLdouble t
Definition: glad.h:2397
SYS_FORCE_INLINE void addExplicitInput(DEP_MicroNode &inp)
Add an input that this micronode depends on.
bool SYSequalZero(const UT_Vector3T< T > &v)
Definition: UT_Vector3.h:1069
static SYS_FORCE_INLINE bool canEvaluateExports()
Global control whether we can evaluate exports.
SYS_FORCE_INLINE bool hasContextOptionDeps() const
Flag accessors.
virtual void evaluateExports()
fpreal64 fpreal
Definition: SYS_Types.h:278
SYS_FORCE_INLINE void setTimeInterested(bool time_interested)
Flag accessors.
SYS_FORCE_INLINE bool isOpDataMicroNode() const
Flag accessors.
Propagation info for a dep micro node.
Definition: DEP_MicroNode.h:36
SYS_FORCE_INLINE void addContextOptionDeps(const DEP_ContextOptionDeps &opts)
Flag accessors.
DEP_API DEP_ContextOptionDeps & DEPcreateContextOptionDepsFromPtr(DEP_ContextOptionDepsPtr &ptr, DEP_ContextOptionDepsLock *lock=nullptr)
SYS_FORCE_INLINE int getNumExplicitOutputs() const
Get the number of non-null outputs.
bool isExprChange() const
Definition: DEP_MicroNode.h:46
#define DEP_API
Definition: DEP_API.h:10
GLint GLsizei count
Definition: glcorearb.h:405
SYS_FORCE_INLINE bool isstring() const
GLenum src
Definition: glcorearb.h:1793