HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PDG_EvaluationContext.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  * COMMENTS:
7  */
8 
9 #ifndef __PDG_EVALUATION_CONTEXT_H__
10 #define __PDG_EVALUATION_CONTEXT_H__
11 
12 #include "PDG_API.h"
13 
14 #include "PDG_AttributeEvaluator.h"
15 #include "PDG_AttributeInfo.h"
16 
17 #include <PY/PY_Result.h>
18 
19 #include <UT/UT_ArrayStringSet.h>
20 #include <UT/UT_ErrorManager.h>
21 #include <UT/UT_Function.h>
22 #include <UT/UT_NonCopyable.h>
23 #include <UT/UT_StringArray.h>
24 #include <UT/UT_StringMap.h>
25 
26 #include <SYS/SYS_Hash.h>
27 
28 #include <iosfwd>
29 
30 class PY_PyObject;
31 class PY_CompiledCode;
33 
35 class PDG_Graph;
36 class PDG_GraphContext;
37 class PDG_Node;
38 class PDG_WorkItem;
39 
40 class UT_IStream;
41 class UT_StringHolder;
42 class UT_WorkBuffer;
43 
44 /*
45  * A context for evaluation PDG Python expression. Each thread-local context has
46  * its own local dictionary which it uses to evaluate expressions, allowing
47  * node authors to insert their own local variables in node callbacks. The dict
48  * is cleared at the beginning of each callback invocation.
49  */
51 {
52 public:
53  /// Evaluation context state
54  enum State
55  {
60  eStateDirtying
61  };
62 
63  /// Enumeration of python script evaluation results
65  {
66  /// The script succeeded without any exceptions
68 
69  /// The script encountered an error or exception
71 
72  /// The script was aborted, e.g. with a sys.exit(..) call
73  eResultAbort
74  };
75 
76  /// Scoped reset of the thread-local context cooking/generation state
78  {
79  public:
80  StateScope(
81  int thread,
82  State state,
83  bool localize,
84  const PDG_Node* node,
85  const PDG_WorkItem* work_item,
86  PDG_GraphContext* context);
87  StateScope(
88  int thread,
89  State state,
90  bool localize,
91  const PDG_Node* node,
92  const PDG_WorkItem* work_item,
93  fpreal time);
94  ~StateScope();
96 
97  private:
98  void init(
99  int thread,
100  State state,
101  bool localize,
102  const PDG_Node* node,
103  const PDG_WorkItem* work_item,
104  fpreal time);
105 
106  private:
107  UT_AutoErrorManager myErrorManager;
108  const PDG_Node* myActiveNode;
109  const PDG_Node* myNode;
110  const PDG_WorkItem* myPreviousItem;
111  PY_PyObject* myLocals;
112  fpreal myEvalTime;
113  int myThread;
114 
115  State myState;
116  bool myParameterError;
117  bool myPushedDir;
118  bool myLocalize;
119  bool myPreviousParent;
120  };
121 
122  /// Scoped setter of local work item
124  {
125  public:
126  ItemScope(int thread,
127  const PDG_WorkItem* work_item,
128  bool is_parent);
129  ~ItemScope();
131 
132  private:
133  const PDG_WorkItem* myPreviousItem;
134  int myThread;
135  bool myPreviousParent;
136  };
137 
138  /// Scoped block that records PDG attribute evaluations
140  {
141  public:
143 
144  public:
148 
149  void reset();
150  void record(const UT_StringHolder& attrib);
151  const UT_StringArray& expressionAttribs() const
152  { return myExpressionAttribs; }
153 
154  private:
155  UT_StringArray myExpressionAttribs;
156  AttribRecordScope* myPreviousRecord;
157  int myThread;
158  };
159 
160  /// Utility function type for converting a PDG_WorkItem* to a PY_PyObject.
162 
163 public:
164  /// Constructs a new context. Should not be called, only here because the
165  /// thread local var needs it to be public instead of private.
168 
170 
171  /// Returns the built-in functions that are available in the the context
172  static void builtinFunctions(UT_StringArray& functions);
173 
174  /// Sets the work item caster function, which is used when setting a work
175  /// item as a Python dictonary variable from C++. If the caster function
176  /// is not installed, a slower code path that looks up the work item from
177  /// the graph is used instead.
178  static void setWorkItemCaster(
179  const WorkItemCaster& caster);
180 
181 
182  /// Configures whether or not all PDG_EvaluationContext instance should
183  /// use Python.
184  static void setUsePython(bool use_python);
185 
186  /// Returns the shared Python context in which expressions evaluated
187  static PY_EvaluationContext& getExpressionContext();
188 
189  /// Returns the thread-local PDG_EvaluationContext instance
190  static PDG_EvaluationContext* getContext();
191 
192  /// Returns the thread-local PDG_EvaluationContext instance for the
193  /// specific thread
194  static PDG_EvaluationContext* getContext(int thread);
195 
196 
197  /// Sets the global batch subitem index. Used when constructing an active
198  /// work item on the job side, to make attributes available.
199  static void setGlobalSubItemIndex(int index,
200  bool dirty);
201 
202  /// Sets the global active work item. Used for setting an active item
203  /// in the current houdini session for debugging, or as part of a houdini-
204  /// based job on the farm.
205  static void setGlobalWorkItem(
206  const PDG_WorkItem* work_item,
207  bool dirty);
208 
209  /// Sets the global active item for an out of process work item job
210  static void setGlobalJobWorkItem(
211  PDG_WorkItem* work_item,
212  const UT_StringHolder& node_name,
213  const UT_StringHolder& scheduler_name);
214 
215  /// Adds the specified attributes to the global set of time dependent
216  /// attribs, for out-of-process batch cooks that have different attribute
217  /// values at each frame.
218  static void setTimeDependentAttribs(
219  const UT_ArrayStringSet& names,
220  bool dirty);
221 
222  /// Dirties all dependent attributes
223  static void dirtyAllAttribs();
224 
225  /// Saves all attributes and field from the global active work item to the
226  /// specified output stream.
227  static bool saveGlobalWorkItem(
228  std::ostream &os,
229  bool binary);
230 
231  /// Loads the data from the specified input stream into a free-standing
232  /// work item, which is saved as the default global item until one is
233  /// selected in the UI.
234  static bool loadGlobalWorkItem(UT_IStream& is);
235 
236  /// Quries the global work item. This should not be used in most cases,
237  /// except for when checking if the global item needs to be cleared
238  static const PDG_WorkItem* globalWorkItem(bool sub_item);
239 
240  /// Returns the global work item only if it's a work item loaded for an
241  /// out of process job, or nullptr in other cases
242  static const PDG_WorkItem* globalJobWorkItem(bool sub_item);
243 
244  /// Queries the global node name. Used on the job side to determine the
245  /// work item name, since the work item does not directly store a string
246  /// name on its own.
247  static const UT_StringHolder& globalNodeName();
248 
249  /// Queries the global scheduler name. Used on the job side to determine
250  /// the submitting scheduler name, since the work item doesn't have direct
251  /// access to the scheduler itself.
252  static const UT_StringHolder& globalSchedulerName();
253 
254  /// Returns true if PDG attribute evaluation is time dependent, else false
255  static bool useTimeDependentAttribs();
256 
257  /// Returns true if the specified attribute is time dependent, else false
258  static bool isTimeDependent(
259  const UT_StringHolder& name);
260 
261  /// Queries the current active work item. If a PDG cook is in-progress, this
262  /// will return the thread-local item. If there is no active cook, this will
263  /// return whatever global work item was set
264  static const PDG_WorkItem* activeWorkItem(int thread);
265 
266  /// Queries the thread local is-parent flag
267  static bool activeIsParent(int thread);
268 
269  /// Returns true if the thread local state is generating
270  static bool isLocalGenerating(int thread);
271 
272  /// Returns true if the thread local state is runtime
273  static bool isLocalRuntime(int thread);
274 
275  /// Returns true if the thread local state indicates the thread is being
276  /// used to do PDG work
277  static bool isLocalActive(int thread);
278 
279  /// Returns true if a PDG job is active, either in process or out of
280  /// process, for the specified thread. Out of process jobs that load in a
281  /// PDG work item are always considered to be active PDG jobs. Otherwise,
282  /// this method falls back to ::isLocalActive.
283  static bool isLocalCookingPDG(int thread);
284 
285  /// Returns the current state of the thread local evaluation context
286  static State localState(int thread);
287 
288  /// Returns the current evaluation time of the thread local context
289  static fpreal localEvalTime(int thread);
290 
291  /// Returns the thread-local active node
292  static const PDG_Node* localActiveNode(int thread);
293 
294 
295  /// Gets an attribute evaluator. Templated so that the caler can
296  /// supply the underlying type
297  template <typename T=PDG_AttributeEvaluator>
298  static PDG_AttributeEvaluator* createAttributeEvaluator(
299  int thread,
300  const char* name)
301  {
302  PDG_EvaluationContext* context =
303  getContext(thread);
304  return context->attributeEvaluator<T>(
305  name);
306  }
307 
308  /// Sets the Python evaluation dictionary directly
309  static void setDict(int thread, PY_PyObject* locals);
310 
311  /// Returns the local Python dictionary object
312  static PY_PyObject* localDict(int thread);
313 
314  /// Sets or updates primitive values in the Python dictionary
315  static void updateDict(int thread,
316  const UT_StringHolder& name,
317  fpreal value);
318  static void updateDict(int thread,
319  const UT_StringHolder& name,
320  int value);
321  static void updateDict(int thread,
322  const UT_StringHolder& name,
323  const UT_StringHolder& value);
324 
325  /// Sets or updates a PDG work in the Python dictionary
326  static void updateDict(int thread,
327  const UT_StringHolder& name,
328  const PDG_WorkItem* work_item);
329 
330  /// Sets or updates a PDG node in the Python dictionary
331  static void updateDict(int thread,
332  const UT_StringHolder& name,
333  const PDG_Node* node);
334 
335  /// Sets or update a PDG graph inthe Python dictionary
336  static void updateDict(int thread,
337  const UT_StringHolder& name,
338  const PDG_Graph* graph);
339 
340  /// Resets the thread-local context's local Python dictionary
341  static void resetDict(int thread);
342 
343 
344  /// Primitive Python eval methods (loat, int, string)
345  static EvaluationResult evaluate(int thread,
346  const PY_CompiledCode& expression,
347  fpreal& result,
348  UT_WorkBuffer& errors);
349  static EvaluationResult evaluate(int thread,
350  const PY_CompiledCode& expression,
351  exint& result,
352  UT_WorkBuffer& errors);
353  static EvaluationResult evaluate(int thread,
354  const PY_CompiledCode& expression,
356  UT_WorkBuffer& errors);
357 
358  /// PyObject eval method
359  static EvaluationResult evaluate(int thread,
360  const PY_CompiledCode& expression,
361  void*& result,
362  UT_WorkBuffer& errors);
363 
364  /// Void/no-result eval method
365  static EvaluationResult evaluate(int thread,
366  const PY_CompiledCode& expression,
367  UT_WorkBuffer& errors);
368 
369  /// Evaluates an abritrary string and returns the PyObject, rather than
370  /// evaluating a compiled code instance.
371  static EvaluationResult evaluateCodeString(
372  int thread,
373  const UT_StringHolder& raw_code,
374  void*& result,
375  bool multi,
376  UT_WorkBuffer& errors);
377 
378  /// Saves a PyObject attribute to a string
379  static bool savePyObjectAttr(
380  int thread,
382  const PDG_AttributePyObject* attr,
383  const UT_StringHolder& module);
384 
385  /// Loads a PyObject attribute to a string
386  static bool loadPyObjectAttr(
387  int thread,
388  void*& result,
389  const UT_StringHolder& attr_data,
390  const UT_StringHolder& module);
391 
392  /// Cooks work item with the specified job script module
393  static bool cookWorkItem(
394  int thread,
395  const UT_StringHolder& module,
396  PDG_WorkItem* work_item,
397  UT_WorkBuffer& errors);
398 
399 
400  /// Evaluates a string literal as a Python object
401  static bool literalEval(
402  int thread,
403  void*& result,
404  const UT_StringHolder& literal,
405  UT_WorkBuffer& errors);
406 
407  /// Hashes a PyOvject attribute
408  static bool hashPyObjectAttr(
410  const PDG_AttributePyObject* attr,
411  UT_WorkBuffer& errors);
412 
413  /// Updates parameter error state
414  static void updateParameterEvaluation(
415  int thread,
416  bool has_error);
417 
418  /// Resets the parameter error state
419  static void resetParameterEvaluation(int thraed);
420 
421 public:
422  /// Returns the context's active work item
423  const PDG_WorkItem* workItem() const;
424 
425  /// Returns true if the local work item is the parent item for the
426  /// evaluation
427  bool isParent() const;
428 
429  /// Returns the active node for the the context
430  const PDG_Node* activeNode() const;
431 
432  /// Returns the state of the context
433  State state() const;
434 
435  /// Returns the parameter evaluation state of the context
436  bool hasParameterError() const;
437 
438  /// Returns the current evaluation time of the context
439  fpreal evalTime() const;
440 
441  /// Returns true if the context is in a generating state
442  bool isGenerating() const
443  { return (myState == eStateStatic) ||
444  (myState == eStateDynamic); }
445 
446  /// Returns true if the context is in a cooking state
447  bool isCooking() const
448  { return (myState == eStateCooking); }
449 
450  /// Returns true if the context is in a runtime state
451  bool isRuntime() const
452  { return (myState == eStateDynamic) ||
453  (myState == eStateCooking) ||
454  (myState == eStateNone); }
455 
456 
457  /// Returns true if the context is actively doing PDG work
458  bool isActive() const
459  { return myState != eStateNone; }
460 
461  /// Returns true if the context should force file paths to be localized
462  bool isLocalize() const
463  { return myIsLocalize; }
464 
465  /// Returns true if the specified work item can be dirtied in the
466  /// current context
467  bool canDirty(const PDG_WorkItem* work_item) const;
468 
469  /// Returns true if the specified node can be dirtied in the current
470  /// context
471  bool canDirty(const PDG_Node* node) const;
472 
473  /// General version of the above method that can be called without a node
474  bool canDirty() const;
475 
476  /// Records an attribute access with the active scope block, if one has
477  /// been set
479  {
480  if (myAttributeRecord)
481  myAttributeRecord->record(name);
482  }
483 
484 private:
485  /// Internal initialize logic
486  void init();
487 
488  /// Internal reset logic
489  void reset();
490 
491  /// Returns the local dictionary
492  PY_PyObject* dict() const;
493 
494  /// Returns the context's local work item
495  const PDG_WorkItem* activeWorkItem() const;
496 
497  /// Returns the context's current attribute record block, or nullptr if
498  /// one has not been set.
499  AttribRecordScope* attributeRecord() const;
500 
501  /// Gets/Sets the local work item
502  void setWorkItem(const PDG_WorkItem* work_item,
503  bool parent);
504 
505  /// Sets the active node for the context
506  void setActiveNode(const PDG_Node* node);
507 
508  /// Sets the context state
509  void setState(State state);
510 
511  /// Sets the context parameter evaluation state
512  void setParameterError(bool has_error);
513 
514  /// Sets the context eval time
515  void setEvalTime(fpreal time);
516 
517  /// Sets the forced localization flag
518  void setLocalize(bool localize);
519 
520  /// Set the active attribute record scope
521  void setAttributeRecord(AttribRecordScope* scope);
522 
523  /// Adds an attribute evaluator to the map, or returns one if it already
524  /// exists. Templated so the caller can select the underlying type.
525  template <typename T>
526  PDG_AttributeEvaluator* attributeEvaluator(const char* name)
527  {
528  auto&& evaluator = myAttributeMap.find(
529  name);
530  if (evaluator == myAttributeMap.end())
531  {
533  new T(name);
534  myAttributeMap[name].reset(eval);
535  return eval;
536  }
537 
538  PDG_AttributeEvaluator* eval =
539  evaluator->second.get();
540  eval->checkTimeDependent();
541 
542  return eval;
543  }
544 
545  /// Generic evaluation method that returns the result of an expression in
546  /// a PY_Result object
547  EvaluationResult evaluate(const PY_CompiledCode& expression,
549  PY_Result& result,
550  bool include_details,
551  UT_WorkBuffer& errors);
552 
553  /// Sets the local dictionary. If the locals object is nullptr, resets the
554  /// dictionary to an empty dict
555  void setLocalDict(PY_PyObject* locals);
556 
557  /// Copies the local dict if it has modifications, else returns a nullptr
558  PY_PyObject* saveLocalDict();
559 
560  /// Restores and frees the local dict
561  void restoreLocalDict(PY_PyObject* locals);
562 
563  /// Sets a local dictionary entry by running a script
564  void setLocalDictEntryByScript(
565  const UT_StringHolder& name,
566  const char* py_expression);
567  /// Sets a local dictionary entry as a PyObject
568  void setLocalDictEntryByObject(
569  const UT_StringHolder& name,
570  PY_PyObject* py_obj);
571 
572 private:
574 
575  PY_PyObject* myLocalDict;
576  const PDG_WorkItem* myActiveWorkItem;
577  const PDG_Node* myActiveNode;
578  EvaluatorMap myAttributeMap;
579  AttribRecordScope* myAttributeRecord;
580  fpreal myEvalTime;
581 
582  State myState;
583 
584  bool myDictModified : 1;
585  bool myIsParent : 1;
586  bool myIsLocalize : 1;
587  bool myHasParameterError : 1;
588 };
589 
590 #endif
CE_API bool evaluate(const CE_OSDRefinement &topo, const CE_OSDEvaluator &eval, const cl::Buffer &coarse, const CE_OSDPatchCoords &patch_coords, const CE_FloatArray *refined_data, cl::Buffer &out, cl::Buffer *du, cl::Buffer *dv)
OIIO_API bool has_error()
Is there a pending global error message waiting to be retrieved?
void
Definition: png.h:1083
GT_API const UT_StringHolder time
GLsizei const GLfloat * value
Definition: glcorearb.h:824
const GLuint GLenum const void * binary
Definition: glcorearb.h:1924
#define PDG_API
Definition: PDG_API.h:23
State
Evaluation context state.
int64 exint
Definition: SYS_Types.h:125
std::size_t SYS_HashType
Define the type for hash values.
Definition: SYS_Hash.h:19
UT_Function< PY_PyObject *(const PDG_WorkItem *)> WorkItemCaster
Utility function type for converting a PDG_WorkItem* to a PY_PyObject.
**But if you need a result
Definition: thread.h:622
EvaluationResult
Enumeration of python script evaluation results.
bool isActive() const
Returns true if the context is actively doing PDG work.
Scoped setter of local work item.
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
GLboolean reset
Definition: glad.h:5138
The script succeeded without any exceptions.
PY_PyObject
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
The script encountered an error or exception.
bool isCooking() const
Returns true if the context is in a cooking state.
HUSD_API bool eval(VtValue &val, T &ret_val)
GLuint const GLchar * name
Definition: glcorearb.h:786
Scoped block that records PDG attribute evaluations.
std::function< T > UT_Function
Definition: UT_Function.h:37
**Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
fpreal64 fpreal
Definition: SYS_Types.h:283
GLuint index
Definition: glcorearb.h:786
bool isRuntime() const
Returns true if the context is in a runtime state.
bool isLocalize() const
Returns true if the context should force file paths to be localized.
bool isGenerating() const
Returns true if the context is in a generating state.
UT_ErrorManager::Scope UT_AutoErrorManager
Alias UT_AutoErrorManager as UT_ErrorManager::Scope.
Scoped reset of the thread-local context cooking/generation state.
void recordAttribute(const UT_StringHolder &name)
state
Definition: core.h:2289