OpenVDB  9.0.1
VolumeExecutable.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file compiler/VolumeExecutable.h
5 ///
6 /// @authors Nick Avramoussis, Francisco Gochez, Richard Jones
7 ///
8 /// @brief The VolumeExecutable, produced by the OpenVDB AX Compiler for
9 /// execution over Numerical OpenVDB Grids.
10 ///
11 
12 #ifndef OPENVDB_AX_COMPILER_VOLUME_EXECUTABLE_HAS_BEEN_INCLUDED
13 #define OPENVDB_AX_COMPILER_VOLUME_EXECUTABLE_HAS_BEEN_INCLUDED
14 
15 #include "CustomData.h"
16 #include "AttributeRegistry.h"
17 #include "AttributeBindings.h"
18 
19 #include <openvdb/version.h>
20 #include <openvdb/Grid.h>
21 
22 #include <unordered_map>
23 
24 class TestVolumeExecutable;
25 
26 namespace llvm {
27 class ExecutionEngine;
28 class LLVMContext;
29 }
30 
31 namespace openvdb {
33 namespace OPENVDB_VERSION_NAME {
34 namespace ax {
35 
36 class Compiler;
37 
38 /// @brief Object that encapsulates compiled AX code which can be executed on a
39 /// collection of VDB volume grids. Executables are created by the compiler
40 /// and hold the final immutable JIT compiled function and context.
41 /// @details The VolumeExecutable is returned from the ax::Compiler when
42 /// compiling AX code for volume execution. The class represents a typical AX
43 /// executable object; immutable except for execution settings and implements
44 /// 'execute' functions which can be called multiple times for arbitrary sets
45 /// of inputs. The intended usage of these executables is to configure their
46 /// runtime arguments and then call VolumeExecutable::execute with your VDBs.
47 /// For example:
48 /// @code
49 /// VolumeExecutable::Ptr exe = compiler.compile<VolumeExecutable>("@a += 1");
50 /// exe->setTreeExecutionLevel(0); // only process leaf nodes
51 /// exe->setValueIterator(VolumeExecutable::IterType::ALL); // process all values
52 /// exe->execute(vdbs); // run on a set of vdbs
53 /// exe->execute(grid); // run on a single vdb
54 /// @endcode
55 ///
56 /// The Volume executable is initialised with specific configurable settings:
57 /// - Iteration Level: min=0, max=RootNode::Level.
58 /// By default, processes the entire VDB tree hierarchy.
59 /// @sa setTreeExecutionLevel
60 /// - Iteration Type: ON
61 /// By default, processes ACTIVE values.
62 /// @sa setValueIterator
63 /// - Active Tile Streaming: ON, OFF or AUTO depending on AX code.
64 /// By default, if AX detects that the AX program may produce unique
65 /// values for leaf level voxels that would otherwise comprise a
66 /// given active tile, this setting is set to ON or AUTO. Otherwise it is
67 /// set to OFF.
68 /// @sa setActiveTileStreaming
69 /// - Grain sizes: 1:32
70 /// The default grain sizes passed to the tbb partitioner for leaf level
71 /// processing and active tile processing.
72 /// @sa setGrainSize
73 /// @sa setActiveTileStreamingGrainSize
74 ///
75 /// For more in depth information, see the @ref vdbaxcompilerexe documentation.
77 {
78 public:
79  using Ptr = std::shared_ptr<VolumeExecutable>;
81 
82  /// @brief Copy constructor. Shares the LLVM constructs but deep copies the
83  /// settings. Multiple copies of an executor can be used at the same time
84  /// safely.
85  VolumeExecutable(const VolumeExecutable& other);
86 
87  ////////////////////////////////////////////////////////
88 
89  ///@{
90  /// @brief Run this volume executable binary on target volumes.
91  /// @details This method reads from the stored settings on the executable
92  /// to determine certain behaviour and runs the JIT compiled function
93  /// across every valid VDB value. Topology may be changed, deleted or
94  /// created.
95  ///
96  /// This method is thread safe; it can be run concurrently from the same
97  /// VolumeExecutable instance on different inputs.
98  ///
99  /// @param grids The VDB Volumes to process
100  void execute(openvdb::GridPtrVec& grids) const;
101  void execute(openvdb::GridBase& grids) const;
102  ///@}
103 
104  ////////////////////////////////////////////////////////
105 
106  /// @brief Set the behaviour when missing grids are accessed. Default
107  /// behaviour is true, which creates them with default transforms and
108  /// background values
109  /// @param flag Enables or disables the creation of missing attributes
110  void setCreateMissing(const bool flag);
111  /// @return Whether this executable will generate new grids.
112  bool getCreateMissing() const;
113 
114  /// @brief Set the execution level for this executable. This controls what
115  /// nodes are processed when execute is called. Possible values depend on
116  /// the OpenVDB configuration in use, however a value of 0 will always
117  /// correspond to the lowest level (leaf-level). By default, the min
118  /// level is zero (LeafNodeType::LEVEL) and the max level is the root
119  /// node's level (RootNodeType::LEVEL). In other words, the default
120  /// execution level settings process the whole of the tree.
121  /// @note A value larger that the number of levels in the tree (i.e. larger
122  /// than the root node's level) will cause this method to throw a runtime
123  /// error.
124  /// @param min The minimum tree execution level to set
125  /// @param max The maximum tree execution level to set
126  void setTreeExecutionLevel(const Index min, const Index max);
127  /// @param level The tree execution level to set. Calls setTreeExecutionLevel
128  /// with min and max arguments as level.
129  void setTreeExecutionLevel(const Index level);
130  /// @brief Get the tree execution levels.
131  /// @param min The minimum tree execution level
132  /// @param max The maximum tree execution level
133  void getTreeExecutionLevel(Index& min, Index& max) const;
134 
135  /// @brief The streaming type of active tiles during execution.
136  /// @param ON active tiles are temporarily densified (converted to leaf
137  /// level voxels) on an "as needed" basis and the subsequent voxel
138  /// values are processed. The temporarily densified node is added to the
139  /// tree only if a non constant voxel buffer is produced. Otherwise a
140  /// child tile may be created or the original tile's value may simply be
141  /// modified.
142  /// @param OFF tile topologies are left unchanged and their single value is
143  /// processed.
144  /// @param AUTO the volume executable analyzes the compiled kernel and
145  /// attempts to determine if expansion of active tiles would lead to
146  /// different, non-constant values in the respective voxels. This is
147  /// done on a per grid basis; ultimately each execution will be set to
148  /// ON or OFF. This option will always fall back to ON if there is any
149  /// chance the kernel may produce child nodes
150  ///
151  /// @note The volume executable always runs an AUTO check on creation and
152  /// will set itself to ON (if all grids always need child nodes), OFF (if
153  /// grids never need child nodes) or remains as AUTO (if this depends on
154  /// which grid is being processed).
155  ///
156  /// @details When an AX kernel is run over coarser levels of the tree (i.e.
157  /// not leaf voxels), it is often desirable to densify these areas into
158  /// unique voxels such that they can each receive a unique value. For
159  /// example, consider the following AX code which assigns a vector volume
160  /// to the world space position of each voxel:
161  /// @code
162  /// v@v = getvoxelpws();
163  /// @endcode
164  /// Active tiles hold a single value but comprise an area greater than
165  /// that of a single voxel. As the above kernel varies with respect to
166  /// a nodes position, we'd need to replace these tiles with leaf voxels
167  /// to get unique per node values. The stream flag is initialised to ON
168  /// in this case.
169  ///
170  /// This behaviour, however, is not always desirable .i.e:
171  /// @code
172  /// v@v = {1,2,3};
173  /// @endcode
174  /// In this instance, all values within a volume receive the same value
175  /// and are not dependent on any spatially or iteratively varying
176  /// metrics. The stream flag is set to OFF.
177  ///
178  /// The AUTO flag is set in cases where the runtime access pattern of the
179  /// inputs determines streaming:
180  /// @code
181  /// f@density = f@mask;
182  /// f@mask = 0;
183  /// @endcode
184  /// In this instance, the runtime topology and values of \@mask determines
185  /// whether child topology needs to be created in \@density, but \@mask
186  /// itself does not need streaming. Streaming will be set to ON for
187  /// density but OFF for mask.
188  ///
189  /// @note This behaviour is only applied to active tiles. If the value
190  /// iterator is set to OFF, this option is ignored.
191  /// @warning This option can generate large amounts of leaf level voxels.
192  /// It is recommended to use a good concurrent memory allocator (such as
193  /// jemalloc) for the best performance.
194  enum class Streaming { ON, OFF, AUTO };
195  /// @brief Controls the behaviour of expansion of active tiles.
196  /// @param s The behaviour to set
197  void setActiveTileStreaming(const Streaming& s);
198  /// @return The current stream behaviour.
199  Streaming getActiveTileStreaming() const;
200  /// @return The current stream behaviour for a particular grid. This is
201  /// either ON or OFF.
202  /// @param name The name of the grid to query
203  /// @param type The grids type
204  Streaming getActiveTileStreaming(const std::string& name,
205  const ast::tokens::CoreType& type) const;
206 
207  enum class IterType { ON, OFF, ALL };
208  /// @brief Set the value iterator type to use with this executable. Options
209  /// are ON, OFF, ALL. Default is ON.
210  /// @param iter The value iterator type to set
211  void setValueIterator(const IterType& iter);
212  /// @return The current value iterator type
213  IterType getValueIterator() const;
214 
215  ///@{
216  /// @brief Set the threading grain sizes used when iterating over nodes
217  /// in a VDB.
218  /// @details Two grain sizes are provided, the first of which (g1) is used
219  /// to determine the chunk size of nodes which are not being streamed (see
220  /// setActiveTileStream). Leaf node execution always uses this grain size.
221  /// The default value for g1 is 1 which is typically appropriate for most
222  /// AX kernels.
223  /// The second grain size is used when streaming execution over active
224  /// tiles in a VDB. This execution model differs significantly from
225  /// typical leaf node execution due to the potential for substantially
226  /// more memory to be allocated. The default value is 32, which works well
227  /// for the default configuration of OpenVDB. If streaming is disabled,
228  /// this value has no effect.
229  /// @note Setting g1 or g2 to zero has the effect of disabling
230  /// multi-threading for the respective node executions. Setting both to
231  /// zero will disable all multi-threading performed by the execute method.
232  void setGrainSize(const size_t g1);
233  void setActiveTileStreamingGrainSize(const size_t g2);
234  /// @return The current g1 grain size
235  /// @sa setGrainSize
236  size_t getGrainSize() const;
237  /// @return The current g2 grain size
238  /// @sa setActiveTileStreamingGrainSize
239  size_t getActiveTileStreamingGrainSize() const;
240  ///@}
241 
242 
243 
244  ////////////////////////////////////////////////////////
245 
246  /// @return The tree execution level.
247  [[deprecated]] Index getTreeExecutionLevel() const;
248 
249  /// @brief Set attribute bindings.
250  /// @param attributeBindings A map of attribute bindings to expected names on
251  /// the geometry to be executed over. By default the AX attributes will be
252  /// bound to volumes of the same name. Supplying bindings
253  /// for a subset of the attributes will leave the others unchanged.
254  /// AX attributes can only bind to a single volume and vice versa.
255  /// However, in a single set call these can be swapped e.g. a -> b and b -> a.
256  /// When bindings are overriden through subsequent calls to this function,
257  /// any dangling volumes will be automatically bound by name.
258  /// To reset these bindings call get function and create a target set of bindings
259  /// for each attribute of name -> name.
260  void setAttributeBindings(const AttributeBindings& bindings);
261  /// @return The current attribute bindings map
262  const AttributeBindings& getAttributeBindings() const;
263 
264  ////////////////////////////////////////////////////////
265 
266  // foward declaration of settings for this executable
267  struct Settings;
268 
269 private:
270  friend class Compiler;
271  friend class ::TestVolumeExecutable;
272 
273  /// @brief Constructor, expected to be invoked by the compiler. Should not
274  /// be invoked directly.
275  /// @param context Shared pointer to an llvm:LLVMContext associated with the
276  /// execution engine
277  /// @param engine Shared pointer to an llvm::ExecutionEngine used to build
278  /// functions. Context should be the associated LLVMContext
279  /// @param accessRegistry Registry of volumes accessed by AX code
280  /// @param customData Custom data which will be shared by this executable.
281  /// It can be used to retrieve external data from within the AX code
282  /// @param functions A map of function names to physical memory addresses
283  /// which were built by llvm using engine
284  /// @param tree The AST linked to this executable. The AST is not stored
285  /// after compilation but can be used during construction of the exe to
286  /// infer some pre/post processing optimisations.
287  VolumeExecutable(const std::shared_ptr<const llvm::LLVMContext>& context,
288  const std::shared_ptr<const llvm::ExecutionEngine>& engine,
289  const AttributeRegistry::ConstPtr& accessRegistry,
290  const CustomData::ConstPtr& customData,
291  const std::unordered_map<std::string, uint64_t>& functions,
292  const ast::Tree& tree);
293 
294 private:
295  // The Context and ExecutionEngine must exist _only_ for object lifetime
296  // management. The ExecutionEngine must be destroyed before the Context
297  const std::shared_ptr<const llvm::LLVMContext> mContext;
298  const std::shared_ptr<const llvm::ExecutionEngine> mExecutionEngine;
299  const AttributeRegistry::ConstPtr mAttributeRegistry;
300  const CustomData::ConstPtr mCustomData;
301  const std::unordered_map<std::string, uint64_t> mFunctionAddresses;
302  std::unique_ptr<Settings> mSettings;
303 };
304 
305 } // namespace ax
306 } // namespace OPENVDB_VERSION_NAME
307 } // namespace openvdb
308 
309 #endif // OPENVDB_AX_COMPILER_VOLUME_EXECUTABLE_HAS_BEEN_INCLUDED
310 
Definition: Compiler.h:31
std::shared_ptr< const CustomData > ConstPtr
Definition: CustomData.h:38
The compiler class. This holds an llvm context and set of compiler options, and constructs executable...
Definition: Compiler.h:49
Abstract base class for typed grids.
Definition: Grid.h:77
std::shared_ptr< VolumeExecutable > Ptr
Definition: VolumeExecutable.h:79
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
std::vector< GridBase::Ptr > GridPtrVec
Definition: Grid.h:514
CoreType
Definition: Tokens.h:31
The Attribute Bindings class is used by the compiled Executables to handle the mapping of AX Attribut...
Definition: Exceptions.h:13
Definition: IndexIterator.h:43
Index32 Index
Definition: Types.h:54
std::shared_ptr< const AttributeRegistry > ConstPtr
Definition: AttributeRegistry.h:42
Object that encapsulates compiled AX code which can be executed on a collection of VDB volume grids...
Definition: VolumeExecutable.h:76
These classes contain lists of expected attributes and volumes which are populated by compiler during...
A Tree is the highest concrete (non-abstract) node in the entire AX AST hierarchy. It represents an entire conversion of a valid AX string.
Definition: AST.h:561
This class wraps an interface for a map of attribute bindings. These map attributes in AX code to con...
Definition: AttributeBindings.h:36
Streaming
The streaming type of active tiles during execution.
Definition: VolumeExecutable.h:194
Access to the CustomData class which can provide custom user user data to the OpenVDB AX Compiler...
IterType
Definition: VolumeExecutable.h:207
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202